You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: ✅ Pattern 15: 0-1 Knapsack (Dynamic Programming).md
+167-4Lines changed: 167 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -163,7 +163,7 @@ This shows that `Banana + Melon` is the best combination as it gives us the `max
163
163
### Basic Brute Force Soultion
164
164
165
165
A basic <b>brute-force solution</b> could be to try all combinations of the given items (as we did above), allowing us to choose the one with `maximum profit` and a weight that doesn’t exceed `C`. Take the example of four items `A, B, C, and D`, as shown in the diagram below. To try all the combinations, our algorithm will look like:
166
-

166
+

167
167
168
168
All <b>green boxes</b> have a total weight that is less than or equal to the capacity `7`, and all the <b>red ones</b> have a weight that is more than `7`. The best solution we have is with items `[B, D]` having a total profit of `22` and a total weight of `7`.
169
169
@@ -230,7 +230,7 @@ console.log(
230
230
### Overlapping Sub-problems
231
231
232
232
Let’s visually draw the recursive calls to see if there are any overlapping sub-problems. As we can see, in each recursive call, `profits` and `weights` arrays remain constant, and only `capacity` and `currIndex` change. For simplicity, let’s denote capacity with `c` and `currIndex` with `i`:
233
-

233
+

234
234
We can clearly see that `c:4, i=3` has been called twice. Hence we have an <b>overlapping sub-problems pattern</b>. We can use <b>[Memoization](https://en.wikipedia.org/wiki/Memoization)</b> to solve <b>overlapping sub-problems</b> efficiently.
235
235
236
236
### Top-down Dynamic Programming with Memoization
@@ -394,7 +394,7 @@ As we know, the final profit is at the bottom-right corner. Therefore, we will s
394
394
As you remember, at every step, we had two options: include an item or skip it. If we skip an item, we take the profit from the remaining items (i.e., from the cell right above it); if we include the item, then we jump to the remaining profit to find more items.
395
395
396
396
Let’s understand this from the above example:
397
-

397
+

398
398
399
399
1.`22` did not come from the top cell (which is `17`); hence we must include the item at index `3` (which is item `D`).
400
400
2. Subtract the profit of item `D` from `22` to get the remaining profit `6`. We then jump to profit `6` on the same row.
@@ -5994,7 +5994,7 @@ if str[strIndex] == pat[patIndex] {
Here is the code for our </b>bottom-up dynamic programming</b> approach:
5997
+
Here is the code for our <b>bottom-up dynamic programming</b> approach:
5998
5998
```js
5999
5999
functionfindSPMCount(str, pattern) {
6000
6000
//every empty pattern has one match
@@ -6130,6 +6130,169 @@ console.log(
6130
6130
- The <b>time complexity</b> of the above algorithm is exponential `O(2ⁿ)`, where `n` is the lengths of the input array.
6131
6131
- The <b>space complexity</b> is `O(n)` which is used to store the <i>recursion stack</i>.
6132
6132
6133
+
### Top-down Dynamic Programming with Memoization
6134
+
To overcome the <b>overlapping subproblems</b>, we can use an array to store the already solved <b>subproblems</b>.
6135
+
6136
+
We need to <b>memoize</b> the <i>recursive functions</i> that calculate the <b>longest decreasing subsequence<b>. The two changing values for our <i>recursive function</i> are the `current` and the `previous` index. Therefore, we can store the results of all <b>subproblems</b> in a two-dimensional array. (Another alternative could be to use a <i>hash-table</i> whose key would be a string (`currIndex` + `“|”` + `prevIndex`)).
6137
+
6138
+
Here is the code:
6139
+
6140
+
````js
6141
+
function findLBSLength(nums) {
6142
+
const lds = [];
6143
+
const ldsReversed = [];
6144
+
6145
+
function findLDSLength(nums, currIndex, prevIndex) {
6146
+
//find the longest decreasing subsequence from
6147
+
//currIndex to the end of the array
6148
+
if (currIndex === nums.length) return 0;
6149
+
6150
+
lds[currIndex] = lds[currIndex] || [];
6151
+
6152
+
if (typeof lds[currIndex][prevIndex + 1] === 'undefined') {
6153
+
//include nums[currIndex] if it is smaller than the previous Number
6154
+
6155
+
let checkWithCurrIndex = 0;
6156
+
6157
+
if (prevIndex === -1 || nums[currIndex] < nums[prevIndex]) {
`Length of Longest Bitonic Subsequence:---> ${findLBSLength([
6219
+
4, 2, 3, 6, 10, 1, 12,
6220
+
])}`
6221
+
);
6222
+
// Output: 5
6223
+
// Explanation: The LBS is {2,3,6,10,1}.
6224
+
6225
+
console.log(
6226
+
`Length of Longest Bitonic Subsequence:---> ${findLBSLength([
6227
+
4, 2, 5, 9, 7, 6, 10, 3, 1,
6228
+
])}`
6229
+
);
6230
+
// Output: 7
6231
+
// Explanation: The LBS is {4,5,9,7,6,3,1}.
6232
+
````
6233
+
6234
+
### Bottom-up Dynamic Programming
6235
+
The above algorithm shows us a clear <b>bottom-up approach</b>. We can separately calculate <b>LDS</b> for every index i.e., from the beginning to the end of the array and vice versa. The required length of <b>LBS</b> would be the one that has the maximum sum of <b>LDS</b> for a given index (from both ends).
6236
+
6237
+
Here is the code for our <b>bottom-up dynamic programming approach</b>:
6238
+
````js
6239
+
function findLBSLength(nums) {
6240
+
const lds = Array(nums.length).fill(0);
6241
+
const ldsReversed = Array(nums.length).fill(0);
6242
+
6243
+
//find the longest decreasing subsequence from
6244
+
//currIndex to the end of the array
6245
+
for (let i = 0; i < nums.length; i++) {
6246
+
//initially set every element of LDS to a length of 1
6247
+
lds[i] = 1;
6248
+
6249
+
for (let j = i - 1; j >= 0; j--) {
6250
+
if (nums[j] < nums[i]) {
6251
+
lds[i] = Math.max(lds[i], lds[j] + 1);
6252
+
}
6253
+
}
6254
+
}
6255
+
6256
+
//find the longest decreasing subsequence from
6257
+
//currIndex to the beginning of the array
6258
+
for (let i = nums.length - 1; i >= 0; i--) {
6259
+
//initially set every element of LDS to a length of 1
0 commit comments