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
As we know, the final profit is at the bottom-right corner. Therefore, we will start from there to find the items that will be going into the knapsack.
390
+
As we know, the final profit is at the bottom-right corner. Therefore, we will start from there to find the items that will be going into the <b>knapsack</b>.
391
391
392
392
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.
393
393
@@ -402,7 +402,7 @@ Let’s understand this from the above example:
402
402
6. Subtract the profit of `B` from `6` to get profit `0`. We then jump to profit `0` on the same row. As soon as we hit zero remaining profit, we can finish our item search.
403
403
7. Thus, the items going into the <b>knapsack</b> are `{B, D}`.
404
404
405
-
Let’s write a function to print the set of items included in the knapsack.
405
+
Let’s write a function to print the set of items included in the <b>knapsack</b>.
- The above solution has time and <b>space complexity</b> of `O(N*C)`, where `N` represents total items and `C` is the maximum capacity.
1774
1774
1775
-
As we know, the final profit is at the right-bottom corner; hence we will start from there to find the items that will be going to the knapsack.
1775
+
As we know, the final profit is at the right-bottom corner; hence we will start from there to find the items that will be going to the <b>knapsack</b>.
1776
1776
1777
1777
As you remember, at every step we had two options: include an item or skip it. If we skip an item, then we take the profit from the cell right above it; if we include the item, then we jump to the remaining profit to find more items.
1778
1778
@@ -1874,7 +1874,7 @@ console.log(
1874
1874
);
1875
1875
```
1876
1876
1877
-
Since this problem is quite similar to <b>[Unbounded Knapsack pattern](#unbounded-knapsack)</b>, let’s jump directly to the bottom-up dynamic solution.
1877
+
Since this problem is quite similar to <b>[Unbounded Knapsack pattern](#unbounded-knapsack)</b>, let’s jump directly to the <b>bottom-up dynamic solution</b>.
> Given a stair with `n` steps, implement a method to count how many possible ways are there to reach the top of the staircase, given that, at every step you can either take `1` step, `2` steps, or `3` steps.
2627
2627
2628
2628
#### Example 1:
2629
-
```
2629
+
```js
2630
2630
Numberofstairs (n) :3
2631
2631
Numberof ways =4
2632
2632
Explanation: Following are the four ways we can climb : {1,1,1}, {1,2}, {2,1}, {3}
2633
2633
```
2634
2634
#### Example 2:
2635
-
````
2635
+
````js
2636
2636
Number of stairs (n) : 4
2637
2637
Number of ways = 7
2638
2638
Explanation: Following are the seven ways we can climb : {1,1,1,1}, {1,1,2}, {1,2,1}, {2,1,1},
@@ -2779,13 +2779,13 @@ console.log(`Number of ways: ---> ${countWays(5)}`);
2779
2779
- The above solution has a <b>time complexity</b> of `O(n)` and a constant <b>space complexity</b> `O(1)`.
2780
2780
2781
2781
#### Fibonacci number pattern
2782
-
We can clearly see that this problem follows the <b>[Fibonacci number pattern](#fibonacci-number-pattern)</b>. The only difference is that in <b>Fibonacci numbers</b> every number is a sum of the two preceding numbers, whereas in this problem every count is a sum of three preceding counts. Here is the recursive formulafor this problem:
2782
+
We can clearly see that this problem follows the <b>[Fibonacci number pattern](#fibonacci-number-pattern)</b>. The only difference is that in <b>Fibonacci numbers</b> every number is a sum of the two preceding numbers, whereas in this problem every count is a sum of three preceding counts. Here is the <i>recursive formula</i>for this problem:
This problem can be extended further. Instead of taking `1`, `2`, or `3` steps at any time, what if we can take up to `k` steps at any time? In that case, our recursive formulawill look like:
2788
+
This problem can be extended further. Instead of taking `1`, `2`, or `3` steps at any time, what if we can take up to `k` steps at any time? In that case, our <i>recursive formula</i>will look like:
> Given a number `n`, implement a method to count how many possible ways there are to express `n` as the sum of `1`, `3`, or `4`.
2799
2799
2800
2800
#### Example 1:
2801
-
```
2801
+
```js
2802
2802
n :4
2803
2803
Numberof ways =4
2804
2804
Explanation: Following are the four ways we can express 'n': {1,1,1,1}, {1,3}, {3,1}, {4}
2805
2805
```
2806
2806
#### Example 2:
2807
-
```
2807
+
```js
2808
2808
n :5
2809
2809
Numberof ways =6
2810
2810
Explanation: Following are the six ways we can express 'n': {1,1,1,1,1}, {1,1,3}, {1,3,1}, {3,1,1},
@@ -2897,7 +2897,7 @@ console.log(`Number of ways: ---> ${countWays(6)}`);
2897
2897
The above solution has time and space complexity of `O(n)`.
2898
2898
2899
2899
#### Fibonacci number pattern
2900
-
We can clearly see that this problem follows the <b>[Fibonacci number pattern](#fibonacci-number-pattern)</b>. However, every number in a <b>Fibonacci series</b> is the sum of the previous two numbers, whereas in this problem every count is a sum of previous three numbers: `previous-1`, `previous-3`, and `previous-4`. Here is the recursive formulafor this problem:
2900
+
We can clearly see that this problem follows the <b>[Fibonacci number pattern](#fibonacci-number-pattern)</b>. However, every number in a <b>Fibonacci series</b> is the sum of the previous two numbers, whereas in this problem every count is a sum of previous three numbers: `previous-1`, `previous-3`, and `previous-4`. Here is the <i>recursive formula</i>for this problem:
@@ -3420,7 +3420,7 @@ Since we want to try all the <b>subsequences</b> of the given <i>sequence</i>, w
3420
3420
1. If the element at the `startIndex` matches the element at the `endIndex`, the length of <b>LPS</b> would be two plus the length of <b>LPS</b> until `startIndex+1` and `endIndex-1`.
3421
3421
2. If the element at the `startIndex` does not match the element at the `endIndex`, we will take the maximum <b>LPS</b> created by either skipping element at the `startIndex` or the `endIndex`.
- The <b>time and space complexity</b> of the above algorithm is `O(n²)`, where `n` is the length of the input string.
3668
3668
3669
3669
#### Manacher’s Algorithm
3670
-
The best-known algorithm to find the <b>[longest palindromic substring](#👩🏽🦯-longest-palindromic-substring)</b> which runs in linear time `O(n)` is <b>[Manacher’s Algorithm](https://en.wikipedia.org/wiki/Longest_palindromic_substring)</b>. However, it is a non-trivial algorithm that doesn’t use <b>DP</b>. Please take a look to familiarize yourself with this algorithm, however, no one expects you to come up with such an algorithm in a 45 minutes coding interview.
3670
+
The best-known algorithm to find the <b>[longest palindromic substring](#👩🏽🦯-longest-palindromic-substring)</b> which runs in linear time `O(n)` is <b>[Manacher’s Algorithm](https://en.wikipedia.org/wiki/Longest_palindromic_substring)</b>. However, it is a non-trivial algorithm that doesn’t use <b>DP</b>. Please take a look to familiarize yourself with this algorithm, however, no one expects you to come up with such an algorithm in a 45 minute coding interview.
- The <b>time complexity</b> of the above algorithm is exponential `O(2ⁿ)`, where `n` represents the total number.
4068
4068
- The <b>space complexity</b> is `O(n)`, which will be used to store the <i>recursion stack</i>.
4069
4069
### Top-down Dynamic Programming with Memoization
4070
-
We can memoizeboth functions `findMPPCutsRecursive()` and `isPalindrome()`. The two changing values in both these functions are the two indexes; therefore, we can store the results of all the <i>subproblems</i> in a two-dimensional array. (alternatively, we can use a <i>hash-table</i>).
4070
+
We can <i>memoize</i>both functions `findMPPCutsRecursive()` and `isPalindrome()`. The two changing values in both these functions are the two indexes; therefore, we can store the results of all the <i>subproblems</i> in a two-dimensional array. (alternatively, we can use a <i>hash-table</i>).
The above solution tells us that we need to build two tables, one for the `isPalindrome()` and one for `findMPPCuts()`.
4143
4143
4144
-
If you remember, we built a table in the [Longest Palindromic Substring (LPS)](#longest-palindromic-subsequence) chapter that can tell us what <i>substrings</i> (of the input <i>string</i>) are <i>palindrome</i>. We will use the same approach here to build the table required for `isPalindrome()`.
4144
+
If you remember, we built a table in the <b>[Longest Palindromic Substring (LPS)](#longest-palindromic-subsequence)</b> chapter that can tell us what <i>substrings</i> (of the input <i>string</i>) are <i>palindrome</i>. We will use the same approach here to build the table required for `isPalindrome()`.
4145
4145
4146
4146
To build the second table for finding the minimum cuts, we can iterate through the first table built for `isPalindrome()`. At any step, if we get a <i>palindrome</i>, we can cut the <i>string</i> there. Which means minimum cuts will be one plus the cuts needed for the <i>remaining string</i>.
> Given a number sequence, find the increasing subsequence with the highest `sum`. Write a method that returns the highest `sum`.
4875
+
4876
+
#### Example 1:
4877
+
```js
4878
+
Input: {4,1,2,6,10,1,12}
4879
+
Output:32
4880
+
Explanation: The increaseing sequence is {4,6,10,12}.
4881
+
Please note the difference, as the LIS is {1,2,6,10,12} which has a sum of'31'.
4882
+
```
4883
+
#### Example 2:
4884
+
```js
4885
+
Input: {-4,10,3,7,15}
4886
+
Output:25
4887
+
Explanation: The increaseing sequences are {10, 15} and {3,7,15}.
4888
+
```
4889
+
4890
+
### Basic Brute Force Solution
4891
+
The problem is quite similar to the <b>[Longest Increasing Subsequence](#👩🏽🦯-🔎-longest-increasing-subsequence)</b>. The only difference is that, instead of finding the increasing subsequence with the maximum length, we need to find an increasing sequence with the maximum `sum`.
4892
+
4893
+
A <b>basic brute-force solution</b> could be to try all the <i>subsequences</i> of the given array. We can process one number at a time, so we have two options at any step:
4894
+
4895
+
1. If the current number is greater than the previous number that we included, we include that number in a running `sum` and make a <i>recursive call</i> for the remaining array.
4896
+
2. We can skip the current number to make a <i>recursive call</i> for the remaining array.
4897
+
4898
+
The highest `sum` of any <i>increasing subsequence</i> would be the max value returned by the two <i>recurse calls</i> from the above two options.
`Maximum Sum Increasing Subsequence is: ---> ${findMSIS([
4933
+
4, 1, 2, 6, 10, 1, 12,
4934
+
])}`
4935
+
);
4936
+
// Output: 32
4937
+
// Explanation: The increaseing sequence is {4,6,10,12}.
4938
+
// Please note the difference, as the LIS is {1,2,6,10,12} which has a sum of '31'.
4939
+
4940
+
console.log(
4941
+
`Maximum Sum Increasing Subsequence is: ---> ${findMSIS([-4, 10, 3, 7, 15])}`
4942
+
);
4943
+
// Output: 25
4944
+
// Explanation: The increaseing sequences are {10, 15} and {3,7,15}.
4945
+
```
4946
+
- The <b>time complexity</b> of the above algorithm is exponential `O(2ⁿ)`, where `n` is the lengths of the input array.
4947
+
- The <b>space complexity</b> is `O(n)` which is used to store the <i>recursion stack</i>.
4948
+
4949
+
### Top-down Dynamic Programming with Memoization
4950
+
We can use <b>memoization</b> to overcome the <i>overlapping subproblems</i>.
4951
+
4952
+
The three changing values for our <i>recursive function</i> are the `currIndex`, the `prevIndex`, and the `sum`. An efficient way of storing the results of the <i>subproblems</i> could be a <i>hash-table</i> whose <i>key</i> would be a string (`currIndex` + `“|”` + `prevIndex` + `“|”` + `sum`).
`Maximum Sum Increasing Subsequence is: ---> ${findMSIS([
4997
+
4, 1, 2, 6, 10, 1, 12,])}`);
4998
+
// Output: 32
4999
+
// Explanation: The increaseing sequence is {4,6,10,12}.
5000
+
// Please note the difference, as the LIS is {1,2,6,10,12} which has a sum of '31'.
5001
+
5002
+
console.log(
5003
+
`Maximum Sum Increasing Subsequence is: ---> ${findMSIS([-4, 10, 3, 7, 15])}`);
5004
+
// Output: 25
5005
+
// Explanation: The increaseing sequences are {10, 15} and {3,7,15}.
5006
+
5007
+
```
5008
+
5009
+
### Bottom-up Dynamic Programming
5010
+
The above algorithm tells us two things:
5011
+
5012
+
1. If the number at the `currIndex` is bigger than the number at the `prevIndex`, we include that number in the `sum` for an increasing sequence up to the `currIndex`.
5013
+
2. But if there is a <b>maximum sum increasing subsequence (MSIS)</b>, without including the number at the `currIndex`, we take that.
5014
+
5015
+
So we need to find all the <i>increasing subsequences</i> for a number at index `i`, from all the previous numbers (i.e. numbers until index `i-1`), to find <b>MSIS</b>.
5016
+
5017
+
If `i` represents the `currIndex` and `j` represents the `prevIndex`, our <i>recursive formula</i> would look like:
5018
+
5019
+
```js
5020
+
if num[i] > num[j] => dp[i] = dp[j] + num[i] if there is no bigger MSISfor'i'
5021
+
```
5022
+
5023
+
Here is the code for our <b>bottom-up dynamic programming approach</b>:
0 commit comments