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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy