Skip to content

Commit d93c6bb

Browse files
Added LC 322 and 927.
1 parent 07faa29 commit d93c6bb

6 files changed

+245
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ Happy to accept any contributions to this in any langugage.
6262
27. [Microsoft OA - Min Moves to Make String without 3 Identical Chars](https://molchevskyi.medium.com/microsoft-interview-tasks-min-moves-to-make-string-without-3-identical-consecutive-letters-abe61ed51a10) | [Solution](./level_medium/MinMovesToMakeStringWithout3IdenticalChars.ts)
6363
28. [Android Unlock Patterns](https://leetcode.com/problems/android-unlock-patterns/) | [Solution 1](./level_medium/LeetCode_351_Android_Unlock.ts) | [Solution 2](/level_medium/LeetCode_351_Android_Unlock_1.ts)
6464
29. [Leet Code 1573 - Number of Ways to Split a String](https://leetcode.com/problems/number-of-ways-to-split-a-string/) | [Solution 1](./level_medium/LeetCode_1573_Number_Of_Ways_To_Split_String_1.ts) | [Solution](./level_medium/LeetCode_1573_Number_Of_Ways_To_Split_String.ts)
65+
30. [Leet Code 322: Coin Change](https://leetcode.com/problems/coin-change/) | [Solution](./level_medium/LeetCode_322_Coins_Change_1.ts) | [Sol 2](./level_medium/LeetCode_322_Coins_Change_2.TS) | [Sol 3](./level_medium/LeetCode_322_Coins_Change.ts)
66+
31. [Leet Code 927 - 3 Equal Parts](https://leetcode.com/problems/three-equal-parts/) | [Solution 1](./level_medium/LeetCode_927_Three_Equal_Parts.ts) | [Solution 1](./level_medium/LeetCode_927_Three_Equal_Parts_1.ts)
6567

6668

6769
## Hard
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Leet Code 322
3+
*
4+
* Solution uses dynamic programming to compute the results for making all target amount from 0 till max for all
5+
* the possible coins denominations from 0 to end. This is because the problem can be divided into sub problems
6+
* as picking a coin leaves up the same problem as original with less target sum.
7+
*
8+
* Brute force
9+
*
10+
* Time: O(m^n) where n is the number of coin denominations and m is the target sum.
11+
* Space: O(n*m) for storing all possible results.
12+
*
13+
* @param coins
14+
* @param amount
15+
*/
16+
function coinChange(coins: number[], amount: number): number {
17+
const totalChange = coinChangeHelper(coins, amount, 0);
18+
return totalChange === Infinity ? -1 : totalChange;
19+
};
20+
21+
function coinChangeHelper(coins: number[], amount: number, current: number): number {
22+
23+
// Return 0 if target amount is 0
24+
if (amount <= 0) return 0;
25+
26+
// All the amount is done using this coin.
27+
if (coins[current] === amount) return 1;
28+
29+
// All the coins are done processing and we do not have a result
30+
if (current >= coins.length) return Infinity;
31+
32+
let coinsWithInclusion = Infinity, coinsWithoutInclusion = Infinity;
33+
if (amount >= coins[current]) {
34+
// A number of current coin denominations can be used.
35+
coinsWithInclusion = 1 + coinChangeHelper(coins, amount - coins[current], current);
36+
}
37+
38+
coinsWithoutInclusion = coinChangeHelper(coins, amount, current + 1);
39+
40+
return Math.min(coinsWithInclusion, coinsWithoutInclusion);
41+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Leet Code 322
3+
*
4+
* Solution uses dynamic programming to compute the results for making all target amount from 0 till max for all
5+
* the possible coins denominations from 0 to end. This is because the problem can be divided into sub problems
6+
* as picking a coin leaves up the same problem as original with less target sum.
7+
*
8+
* The solution uses the top down approach to compute all the results.
9+
*
10+
* Time: O(n*m) where n is the number of coin denominations and m is the target sum.
11+
* Space: O(n*m) for storing all possible results.
12+
*
13+
* @param coins
14+
* @param amount
15+
*/
16+
function coinChange(coins: number[], amount: number): number {
17+
const cache: number[][] = Array.from({length: coins.length + 1}, () => Array(amount));
18+
const totalChange = coinChangeHelper(coins, amount, 0, cache);
19+
return totalChange === Infinity ? -1 : totalChange;
20+
};
21+
22+
function coinChangeHelper(coins: number[], amount: number, current: number, cache: number[][]): number {
23+
24+
// Return 0 if target amount is 0
25+
if (amount <= 0) return 0;
26+
27+
// All the amount is done using this coin.
28+
if (coins[current] === amount) return 1;
29+
30+
// All the coins are done processing and we do not have a result
31+
if (current >= coins.length) return Infinity;
32+
33+
if (cache[current][amount] !== undefined) return cache[current][amount];
34+
35+
let coinsWithInclusion = Infinity, coinsWithoutInclusion = Infinity;
36+
if (amount >= coins[current]) {
37+
// A number of current coin denominations can be used.
38+
coinsWithInclusion = 1 + coinChangeHelper(coins, amount - coins[current], current, cache);
39+
}
40+
41+
coinsWithoutInclusion = coinChangeHelper(coins, amount, current + 1, cache);
42+
43+
cache[current][amount] = Math.min(coinsWithInclusion, coinsWithoutInclusion);
44+
return cache[current][amount];
45+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Leet Code 322
3+
*
4+
* Solution uses dynamic programming to compute the results for making all target amount from 0 till max for all
5+
* the possible coins denominations from 0 to end. This is because the problem can be divided into sub problems
6+
* as picking a coin leaves up the same problem as original with less target sum.
7+
*
8+
* The solution uses the bottoms up approach to compute all the results.
9+
*
10+
* Time: O(n*m) where n is the number of coin denominations and m is the target sum.
11+
* Space: O(n*m) for storing all possible results.
12+
*
13+
* @param coins
14+
* @param amount
15+
*/
16+
function coinChange(coins: number[], amount: number): number {
17+
18+
// Create a DP Table
19+
const dpTable: number[][] = Array.from({length: coins.length + 1}, () => Array(amount + 1).fill(Infinity));
20+
21+
// For all the amount with a single coin, we calculate the initial min coins.
22+
for (let amt = 1; amt <= amount; amt++) {
23+
if (amt % coins[0] === 0) {
24+
dpTable[0][amt] = Math.floor(amt / coins[0]);
25+
} else {
26+
dpTable[0][amt] = Infinity;
27+
}
28+
}
29+
30+
// For amount 0, we need 0 coins.
31+
for (let coin = 0; coin < coins.length; coin++) dpTable[coin][0] = 0;
32+
33+
// Calculate rest of the figures.
34+
for (let coin = 1; coin < coins.length; coin++) {
35+
for (let amt = 1; amt <= amount; amt++) {
36+
37+
// Only if the new amount is greater than the coin.
38+
if (amt >= coins[coin]) {
39+
dpTable[coin][amt] = 1 + dpTable[coin][amt - coins[coin]];
40+
}
41+
42+
// Also try without adding the current coin.
43+
dpTable[coin][amt] = Math.min(dpTable[coin][amt], dpTable[coin - 1][amt])
44+
}
45+
}
46+
47+
const result = dpTable[coins.length - 1][amount];
48+
return result === Infinity ? -1 : result;
49+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function threeEqualParts(A: number[]): number[] {
2+
for (let left = 0; left < A.length - 2; left++) {
3+
for (let right = left + 2; right < A.length; right++) {
4+
if (haveEqualParts(left, right, A)) {
5+
return [left, right];
6+
}
7+
}
8+
}
9+
10+
return [-1, -1];
11+
};
12+
13+
function haveEqualParts(left: number, right: number, A: number[]): boolean {
14+
const decimalVal1 = binaryToDecimal(A, 0, left);
15+
const decimalVal2 = binaryToDecimal(A, left + 1, right - 1);
16+
const decimalVal3 = binaryToDecimal(A, right, A.length - 1);
17+
return decimalVal1 === decimalVal2 && decimalVal2 === decimalVal3;
18+
}
19+
20+
function binaryToDecimal(A: number[], left: number, right: number) {
21+
let total = 0, base = 1;
22+
for (let val = right; val >= left; val--) {
23+
total += base * A[val];
24+
base *= 2;
25+
}
26+
return total;
27+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Leet Code 927
3+
*
4+
* Solution is based on the fact that the number of 1s will be equal and hence there boundaries can be identified
5+
* using a single iteration. We just need to identify the number of zeroes in between and ignore those (assign to the right).
6+
*
7+
* Time: O(n), space: O(1)
8+
*
9+
* @param A
10+
*/
11+
function threeEqualParts(A: number[]): number[] {
12+
13+
// Return negative, cannot be divided.
14+
const totalOnes = countOnes(A);
15+
if (totalOnes % 3 !== 0) return [-1, -1];
16+
if (totalOnes === 0) return [0, A.length - 2];
17+
18+
const maxPartOnes = totalOnes/3;
19+
20+
// Critical Path will return {left, right} + zeros.
21+
const cp = findCriticalPath(A, maxPartOnes);
22+
if (cp === undefined) return [-1, -1];
23+
24+
// Middle Critical Path will return {left, right}
25+
const midCp = matchCriticalPath(A, cp);
26+
if (midCp === undefined) return [-1, -1];
27+
28+
// Left Critical Path will return {left, right}
29+
const leftCp = matchCriticalPath(A, midCp);
30+
if (leftCp === undefined || hasMostSigOne(A, leftCp.left - 1)) return [-1, -1];
31+
32+
return [leftCp.right, midCp.right + 1];
33+
};
34+
35+
function hasMostSigOne(A: number[], start: number) {
36+
for (let pos = start; pos >= 0; pos--) if (A[pos] !== 0) return true
37+
}
38+
39+
// Matches the critical path of the current part to the right part. Do the adjustments for any gaps of zeros.
40+
function matchCriticalPath(A: number[], {left, right, zeros}) {
41+
42+
// Get all the leading zeros so far.
43+
let newPos = left - 1, thisZeros = 0;
44+
while(A[newPos] === 0) {
45+
thisZeros++;
46+
newPos--;
47+
}
48+
49+
// Break if not matching with enough trailing zeros.
50+
if (thisZeros < zeros) return undefined;
51+
52+
// Break if the critical path is not matching.
53+
for (let oldPos = right - zeros; oldPos >= left; oldPos--) {
54+
if (A[newPos--] !== A[oldPos]) return undefined;
55+
}
56+
57+
// All fine, adjust the bounds and return;
58+
return {
59+
left: newPos + 1,
60+
right: (left - 1) - (thisZeros - zeros),
61+
zeros,
62+
}
63+
}
64+
65+
function findCriticalPath(A: number[], maxPartOnes: number) {
66+
let ones = 1, zeros = 0, pos = A.length - 1;
67+
while(A[pos--] === 0) zeros++;
68+
while(ones < maxPartOnes) {
69+
if (A[pos--] === 1) {
70+
ones++;
71+
}
72+
}
73+
74+
return {left: pos + 1, right: A.length - 1, zeros};
75+
}
76+
77+
function countOnes(A: number[]) {
78+
return A.filter(val => val === 1).length;
79+
}
80+
81+
console.log(threeEqualParts([1,1,1,0,1,0,0,1,0,1,0,0,0,1,0,0,1,1,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,0,1,0,0]));

0 commit comments

Comments
 (0)