├── 1D - DP on Jump Patterns ├── DpFibonacci.cpp ├── Frog Jumps for 2 steps.cpp ├── Frog Jumps for K steps.cpp ├── Horse Robber 2.cpp ├── Maximum sum of non-adjacent elements(House Robber).cpp └── N-stairs.cpp ├── 2D - DP on Grid ├── Grid Unique Paths 2.cpp ├── Grid Unique Paths.cpp ├── Minimum Falling Path Sum.cpp ├── Minimum Path Sum.cpp ├── Ninja Training.cpp └── Triangle.cpp ├── 3D - DP on Grid + DP On stocks ├── Best Time to Buy & sell stocks 3.cpp ├── Best Time to Buy & sell stocks 4.cpp └── Cherry Pickup.cpp ├── DP On Increasing Subsequences ├── Largest Divisible Subset(LIS).cpp ├── Longest Bitonic Subsequence.cpp ├── Longest Increasing Subsequence(LIS)-Binary Search.cpp ├── Longest Increasing Subsequence(LIS).cpp ├── Longest String chain.cpp ├── Number of Longest Increasing Subsequences.cpp └── Printing the Longest Increasing Subsequence(LIS).cpp ├── DP On Partitions(MCM) Pattern ├── Boolean Evaluation.cpp ├── Burst Balloons.cpp ├── Count square submatrices with all 1s.cpp ├── Matrix Chain Multiplication Memoization.cpp ├── Matrix Chain Multiplication Tabulation.cpp ├── Maximum rectangle area with all 1s.cpp ├── Minimum cost to cut the Stick.cpp ├── Palindrome Partition.cpp └── Partition array for Maximum sum.cpp ├── DP on Stocks ├── Best Time to Buy & Sell stock with Cooldown.cpp ├── Best Time to Buy & Sell stocks with Transaction Fees.cpp ├── Best Time to Buy & sell stocks 2.cpp ├── Best Time to Buy & sell stocks 3.cpp ├── Best Time to Buy & sell stocks 4.cpp └── Best Time to Buy & sell stocks.cpp ├── DP on Strings ├── Distinct Subsequences.cpp ├── Edit Distance.cpp ├── Longest Common Subsequence.cpp ├── Longest Common Substring.cpp ├── Longest Palindromic Subsequence.cpp ├── Minimum Insertions To convert a string into Palindromic String.cpp ├── Minimum Number of Insertion-Deletions to Make both strings Equal.cpp ├── Print Longest Common Subsequence.cpp ├── Shortest Common Supersequence.cpp └── Wildcard Matching.cpp ├── DP on Subsequences ├── 0-1 Knapsack.cpp ├── Coin change 2.cpp ├── Count Partitions With Given Difference.cpp ├── Count Subset with sum K.cpp ├── Minimum Coins.cpp ├── Partition Equal subset sum.cpp ├── Partition a set into two subsets such that the difference of subset sums is minimum.cpp ├── Rod Cutting Problem.cpp ├── Subset Sum Equals to Target.cpp ├── Target sum.cpp └── Unbounded Knapsack.cpp └── Readme.md /1D - DP on Jump Patterns/DpFibonacci.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | const int mod = 1e9 + 7; 5 | 6 | //program using dp of fibonacci series to give the nth fibonacci number using memoization 7 | 8 | int giveNthFibonacciUsingMemoization(int n, vector &dp) { 9 | if (n <= 1) return n;// base case for the first two numbers which are fixed as 0 and 1. 10 | if (dp[n] != -1)return dp[n]; 11 | return dp[n] = giveNthFibonacciUsingMemoization(n - 1, dp) + giveNthFibonacciUsingMemoization(n - 2, dp); 12 | } 13 | 14 | //program using tabulation 15 | int giveNthFibonacciUsingTabulation(int n, vector &dp) { 16 | dp[0] = 0, dp[1] = 1; 17 | for (int i = 2; i <= n; i++)dp[i] = dp[i - 1] + dp[i - 2]; 18 | return dp[n]; 19 | } 20 | 21 | 22 | //now the complexity of both the codes is (space and time ) O(N) in the below approach we are goiing to reduce the extra space 23 | int giveNthFibonacci(int n) { 24 | int first = 0, second = 1, third; 25 | while (n - 2 >= 0) { 26 | third = first + second; 27 | first = second; 28 | second = third; 29 | n--; 30 | } 31 | return second; 32 | } 33 | 34 | //main function which holds the answer 35 | 36 | int main() { 37 | int num; 38 | cin >> num; 39 | vector dp(num + 1, -1); 40 | // cout << giveNthFibonacciUsingMemoization(num, dp) << " "; 41 | // cout << giveNthFibonacciUsingTabulation(num, dp) << " "; 42 | cout << giveNthFibonacci(num) << " "; 43 | return 0; 44 | } 45 | 46 | -------------------------------------------------------------------------------- /1D - DP on Jump Patterns/Frog Jumps for 2 steps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | //most optimised code without using any extra space 6 | int frogJump(int n, vector &heights) 7 | { 8 | // Write your code here. 9 | int fPrev = 0, sPrev = 0, currAns; 10 | for (int i = 1; i < n; i++) { 11 | int left = fPrev + abs(heights[i] - heights[i - 1]); 12 | int right = INT_MAX; 13 | if (i > 1) right = sPrev + abs(heights[i] - heights[i - 2]); 14 | //find the min of both 15 | currAns = min(left, right); 16 | sPrev = fPrev; 17 | fPrev = currAns; 18 | } 19 | return fPrev; 20 | } 21 | 22 | 23 | 24 | 25 | // ==> Tabulation approach reduced a extra stack space of the recursion 26 | int frogJumpTab(int n, vector &heights) 27 | { 28 | // Write your code here. 29 | vector dp(n, -1); 30 | dp[0] = 0; //somwhat type a base case 31 | for (int i = 1; i < n; i++) { 32 | int left = dp[i - 1] + abs(heights[i] - heights[i - 1]); 33 | int right = INT_MAX; 34 | 35 | if (i > 1) right = dp[i - 2] + abs(heights[i] - heights[i - 2]); 36 | //find the min of both 37 | dp[i] = min(left, right); 38 | } 39 | return dp[n - 1]; 40 | } 41 | 42 | 43 | 44 | 45 | // ==> Memoisation approach using Extra space with a recursion stack space 46 | int frogJump(int i, vector &heights, vector &dp) { 47 | //we start moving from the last thats why the base is this 48 | if (i == 0)return 0; 49 | if (dp[i] != -1) return dp[i]; 50 | int left = frogJump(i - 1, heights, dp) + abs(heights[i] - heights[i - 1]); 51 | int right = INT_MAX; 52 | if (i > 1) right = frogJump(i - 2, heights, dp) + abs(heights[i] - heights[i - 2]); 53 | return dp[i] = min(left, right); 54 | } 55 | 56 | 57 | int main() { 58 | int n; 59 | cin >> n; 60 | vector heights(n); 61 | vector dp(n + 1, -1); 62 | for (int &i : heights) cin >> i; 63 | // cout << frogJump(n, heights) << endl; 64 | cout << frogJumpTab(n, heights) << endl; 65 | // cout << frogJump(n, heights, dp) << endl; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /1D - DP on Jump Patterns/Frog Jumps for K steps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //using basic recursion 5 | int frogJumpKSteps(int ind, int k, vector &heights) { 6 | if (ind == 0) return 0;//base case 7 | //now for the k steps 8 | int minSteps = INT_MAX; 9 | for (int j = 1; j <= k; j++) { 10 | if (ind - j >= 0) { 11 | int jumps = frogJumpKSteps(ind - j, k, heights) + abs(heights[ind] - heights[ind - j]); 12 | minSteps = min(minSteps, jumps); 13 | } 14 | } 15 | return minSteps; 16 | 17 | } 18 | 19 | //another approach using memoization 20 | int frogJumpKSteps(int ind, int k, vector &heights, vector &dp) { 21 | if (ind == 0) return 0;//base case 22 | //now for the k steps 23 | if (dp[ind] != -1) return dp[ind]; 24 | int minSteps = INT_MAX; 25 | for (int j = 1; j <= k; j++) { 26 | if (ind - j >= 0) { 27 | int jumps = frogJumpKSteps(ind - j, k, heights, dp) + abs(heights[ind] - heights[ind - j]); 28 | minSteps = min(minSteps, jumps); 29 | } 30 | } 31 | return dp[ind] = minSteps; 32 | 33 | } 34 | 35 | //another approach using tabulation 36 | int frogJumpKStepsTab(int n, int k, vector &heights) { 37 | vector dp(n, -1); 38 | dp[0] = 0;//base case 39 | for (int i = 1; i < n; i++) { 40 | int minSteps = INT_MAX; 41 | for (int j = 1; j <= k; j++) { 42 | if (i - j >= 0) { 43 | int jumps = dp[i - j] + abs(heights[i] - heights[i - j]); 44 | minSteps = min(minSteps, jumps); 45 | } 46 | } 47 | dp[i] = minSteps; 48 | } 49 | return dp[n - 1]; 50 | } 51 | 52 | 53 | //main function 54 | int main() { 55 | int n, k; cin >> n >> k; 56 | vector heights(n); 57 | vector dp(n, -1); 58 | for (int &i : heights)cin >> i; 59 | // cout << frogJumpKSteps(n - 1, k, heights) << endl; 60 | cout << frogJumpKStepsTab(n, k, heights) << endl; 61 | // cout << frogJumpKSteps(n - 1, k, heights, dp) << endl; 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /1D - DP on Jump Patterns/Horse Robber 2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | long long int maximumNonAdjacentSumSpaceOpt(vector &nums) { 6 | int n = nums.size(); 7 | long long int prev = nums[0], prev2 = 0, currI = 0; 8 | for (int i = 1 ; i < n; i++) { 9 | long long int pick = nums[i]; 10 | if (i > 1) pick += prev2; 11 | long long int notPick = prev; 12 | currI = max(pick, notPick); 13 | prev2 = prev; 14 | prev = currI; 15 | } 16 | return prev; 17 | } 18 | 19 | long long int houseRobber(vector& valueInHouse) 20 | { 21 | // Write your code here. 22 | int n = valueInHouse.size(); 23 | if (n == 1) return valueInHouse[0]; 24 | vector withoutFirst, withoutLast; 25 | for (int i = 0; i < n; i++) { 26 | if (i != 0) withoutFirst.push_back(valueInHouse[i]); 27 | if (i != n - 1) withoutLast.push_back(valueInHouse[i]); 28 | } 29 | int ansWithoutFirst = maximumNonAdjacentSumSpaceOpt(withoutFirst); 30 | int ansWithoutLast = maximumNonAdjacentSumSpaceOpt(withoutLast); 31 | return max(ansWithoutLast, ansWithoutFirst); 32 | 33 | } 34 | 35 | int main() { 36 | int n; 37 | cin >> n; 38 | vector nums(n); 39 | for (int &i : nums) cin >> i; 40 | cout << houseRobber(nums) << endl; 41 | } 42 | -------------------------------------------------------------------------------- /1D - DP on Jump Patterns/Maximum sum of non-adjacent elements(House Robber).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | //this is the recursive and memoization solution for the problem 6 | 7 | int findMaxAmongAll(int i, vector &a, vector &dp) { 8 | //base case 9 | if (i == 0) return a[i]; 10 | if (i < 0) return 0; 11 | if (dp[i] != -1) return dp[i]; 12 | int pick = a[i] + findMaxAmongAll(i - 2, a, dp); 13 | int notPick = findMaxAmongAll(i - 1, a, dp); 14 | return dp[i] = max(pick, notPick); 15 | } 16 | 17 | 18 | //tabulation of the same problem 19 | int maximumNonAdjacentSumTabul(vector &nums) { 20 | int n = nums.size(); 21 | vector dp(n, -1); 22 | //base case 23 | dp[0] = nums[0]; 24 | for (int i = 1; i < n; i++) { 25 | int pick = pick = nums[i]; 26 | if (i > 1)pick += dp[i - 2]; 27 | int notPick = dp[i - 1]; 28 | dp[i] = max(pick, notPick); 29 | } 30 | return dp[n - 1]; 31 | } 32 | 33 | 34 | //most optimal solution using space optimisation 35 | 36 | int maximumNonAdjacentSumSpaceOpt(vector &nums) { 37 | int n = nums.size(); 38 | int prev = nums[0], prev2 = 0, currI = 0; 39 | for (int i = 1 ; i < n; i++) { 40 | int pick = nums[i]; 41 | if (i > 1) pick += prev2; 42 | int notPick = prev; 43 | currI = max(pick, notPick); 44 | prev2 = prev; 45 | prev = currI; 46 | } 47 | return prev; 48 | } 49 | 50 | int maximumNonAdjacentSum(vector &nums) { 51 | // Write your code here. 52 | int n = nums.size(); 53 | vector dp(n + 1, -1); 54 | return findMaxAmongAll(n - 1, nums, dp); 55 | } 56 | 57 | int main() { 58 | int n; 59 | cin >> n; 60 | vector nums(n); 61 | for (int &i : nums) cin >> i; 62 | // cout << maximumNonAdjacentSum(nums) << endl; 63 | // cout << maximumNonAdjacentSumTabul(nums) << endl; 64 | cout << maximumNonAdjacentSumSpaceOpt(nums) << endl; 65 | } -------------------------------------------------------------------------------- /1D - DP on Jump Patterns/N-stairs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | const int mod = 1e9 + 7; 5 | 6 | int nStairs(long long n, vector &dp) { 7 | if (n == 0 || n == 1) return 1; 8 | dp[1] = 1, dp[2] = 2; 9 | for (int i = 3; i <= n; i++)dp[i] = ( dp[i - 1] % mod + dp[i - 2] % mod) % mod; 10 | return dp[n]; 11 | } 12 | 13 | 14 | //main function which holds the answer 15 | 16 | int main() { 17 | int num; 18 | for (int i = 1; i <= 9; i++ ) { 19 | cin >> num; 20 | vector dp(num + 1, -1); 21 | cout << nStairs(num, dp) << " "; 22 | } 23 | return 0; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /2D - DP on Grid/Grid Unique Paths 2.cpp: -------------------------------------------------------------------------------- 1 | /*======= GRID UNIQUE PATHS - II ============================*/ 2 | /* In leetcode obstacles are treated as 1 and on code studio they are treated as -1 so by that take the values accordingly*/ 3 | #include 4 | using namespace std; 5 | 6 | 7 | /*Recursive approach TC - 2^(m*n) and SC = O(path length) */ 8 | int givePathsRecursive2(int m , int n, vector> &grid) { 9 | //check for the obstacles 10 | if (m >= 0 and n >= 0 and grid[m][n] == -1) return 0; 11 | if (m == 0 and n == 0) return 1;//reached the destination 12 | if (m < 0 or n < 0) return 0;//out of bounds 13 | int left = givePathsRecursive2(m, n - 1, grid); 14 | int up = givePathsRecursive2(m - 1, n, grid); 15 | return up + left; 16 | } 17 | 18 | /*Memoisation approach TC = O(M*N) and SC = O(M*N) + O(path length) */ 19 | 20 | int givePathsMemo2(int m , int n, vector> &dp, vector> &grid) { 21 | //check for the obstacles 22 | if (m >= 0 and n >= 0 and grid[m][n] == -1) return 0; 23 | if (m == 0 and n == 0) return 1;//reached the destination 24 | if (m < 0 or n < 0) return 0;//out of bounds 25 | if (dp[m][n] != -1) return dp[m][n]; 26 | return dp[m][n] = givePathsMemo2(m - 1, n, dp, grid) + givePathsMemo2(m, n - 1, dp, grid); 27 | } 28 | 29 | /*Tabulation approach TC = O(M*N) and SC = O(M*N)*/ 30 | int givePathsTabu2(int m, int n, vector> &grid) { 31 | vector> dp(m, vector(n, 0)); 32 | for (int i = 0 ; i < m; i++) { 33 | for (int j = 0; j < n; j++) { 34 | if (grid[i][j] == -1) dp[i][j] = 0; 35 | else if (i == 0 and j == 0)dp[i][j] = 1; 36 | else { 37 | int left = 0, up = 0; 38 | if (j > 0) 39 | left = dp[i][j - 1]; 40 | if (i > 0) 41 | up = dp[i - 1][j]; 42 | dp[i][j] = up + left; 43 | } 44 | } 45 | 46 | } 47 | return dp[m - 1][n - 1]; 48 | } 49 | 50 | /*Space optimisation - TC - O(M*N) and SC - O(N)*/ 51 | int givePathsMostOptimal2(int m, int n, vector> &grid) { 52 | vector< int> prev(n); 53 | for (int i = 0; i < m; i++) { 54 | vector curr(n); 55 | for (int j = 0; j < n; j++) { 56 | if (grid[i][j] == -1) curr[j] = 0; 57 | else if (i == 0 and j == 0) curr[j] = 1; 58 | else { 59 | int up = 0, left = 0; 60 | if (i > 0) up = prev[j]; 61 | if (j > 0) left = curr[j - 1]; 62 | curr[j] = (up + left); 63 | } 64 | } 65 | prev = curr; 66 | } 67 | return prev[n - 1]; 68 | } 69 | 70 | 71 | 72 | 73 | int uniquePaths(int m, int n, vector> &grid) { 74 | vector> dp(m, vector(n, -1)); 75 | //recursive approach 76 | // int ans = givePathsRecursive2(m - 1, n - 1, grid); 77 | 78 | //memoise approach 79 | // int ans = givePathsMemo2(m - 1, n - 1, dp, grid); 80 | 81 | //tabulation approach 82 | // int ans = givePathsTabu2(m, n, grid); 83 | 84 | int ans = givePathsMostOptimal2(m, n, grid); 85 | 86 | return ans; 87 | } 88 | int main() { 89 | 90 | int m, n; 91 | cin >> m >> n; 92 | vector> grid(m, vector (n)); 93 | for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) cin >> grid[i][j]; 94 | cout << uniquePaths(m, n, grid) << endl; 95 | return 0; 96 | 97 | } -------------------------------------------------------------------------------- /2D - DP on Grid/Grid Unique Paths.cpp: -------------------------------------------------------------------------------- 1 | /*======= GRID UNIQUE PATHS ============================*/ 2 | 3 | #include 4 | using namespace std; 5 | 6 | 7 | /*Recursive approach TC - 2^(m*n) and SC = O(path length) */ 8 | int givePathsRecursive(int m , int n) { 9 | if (m == 0 and n == 0) return 1; 10 | if (m < 0 or n < 0) return 0; 11 | int left = givePathsRecursive(m, n - 1); 12 | int up = givePathsRecursive(m - 1, n); 13 | return up + left; 14 | } 15 | 16 | /*Memoisation approach TC = O(M*N) and SC = O(M*N) + O(path length) */ 17 | 18 | int givePathsMemo(int m , int n, vector> &dp) { 19 | if (m == 0 and n == 0) return 1; 20 | if (m < 0 or n < 0) return 0; 21 | if (dp[m][n] != -1) return dp[m][n]; 22 | return dp[m][n] = givePathsMemo(m - 1, n, dp) + givePathsMemo(m, n - 1, dp); 23 | } 24 | 25 | /*Tabulation approach TC = O(M*N) and SC = O(M*N)*/ 26 | int givePathsTabu(int m, int n) { 27 | vector> dp(m, vector(n, 0)); 28 | for (int i = 0 ; i < m; i++) { 29 | for (int j = 0; j < n; j++) { 30 | int left = 0, up = 0; 31 | if (i == 0 and j == 0)dp[0][0] = 1; 32 | else { 33 | if (j > 0) 34 | left = dp[i][j - 1]; 35 | if (i > 0) 36 | up = dp[i - 1][j]; 37 | dp[i][j] = up + left; 38 | } 39 | } 40 | 41 | } 42 | return dp[m - 1][n - 1]; 43 | } 44 | 45 | /*Space optimisation - TC - O(M*N) and SC - O(N)*/ 46 | int givePathsMostOptimal(int m, int n) { 47 | vector prev(n); 48 | for (int i = 0 ; i < m; i++) { 49 | vector temp(n);//basically this is the current row having n columns 50 | for (int j = 0; j < n; j++) { 51 | if (i == 0 and j == 0)temp[j] = 1; 52 | else { 53 | int up = 0, left = 0; 54 | if (j > 0) 55 | left = temp[j - 1]; 56 | if (i > 0) 57 | up = prev[j]; 58 | temp[j] = up + left; 59 | } 60 | } 61 | prev = temp; 62 | } 63 | return prev[n - 1]; 64 | } 65 | 66 | 67 | 68 | 69 | int uniquePaths(int m, int n) { 70 | // vector> dp(m, vector(n, -1)); 71 | //recursive approach 72 | // int ans = givePathsRecursive(m - 1, n - 1); 73 | 74 | //memoise approach 75 | // int ans = givePathsMemo(m - 1, n - 1, dp); 76 | 77 | //tabulation approach 78 | // int ans = givePathsTabu(m, n); 79 | 80 | int ans = givePathsMostOptimal(m, n); 81 | 82 | return ans; 83 | } 84 | 85 | int main() { 86 | int m, n; 87 | cin >> m >> n; 88 | cout << uniquePaths(m, n) << endl; 89 | return 0; 90 | 91 | } -------------------------------------------------------------------------------- /2D - DP on Grid/Minimum Falling Path Sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define INF 1e9 5 | 6 | /*Recursive Approach */ 7 | int findMinimumPathFallingSum(vector> &mat, int ind, int exploreCols) { 8 | //base case if the row is first then accordingly find the minimum 9 | if (exploreCols < 0 or exploreCols >= mat.size()) return INF; 10 | if (ind == 0) return mat[0][exploreCols]; 11 | //another base case if our index is move out of bound 12 | int upward = mat[ind][exploreCols] + findMinimumPathFallingSum(mat, ind - 1, exploreCols); 13 | int leftDiagonal = mat[ind][exploreCols] + findMinimumPathFallingSum(mat, ind - 1, exploreCols - 1); 14 | int rightDiagonal = mat[ind][exploreCols] + findMinimumPathFallingSum(mat, ind - 1, exploreCols + 1); 15 | return min({leftDiagonal, upward, rightDiagonal}); 16 | } 17 | 18 | 19 | 20 | /*Memoisation Approach */ 21 | int findMinimumPathFallingSumUsingMemo(vector> &mat, int ind, int exploreCols, vector> &memo) { 22 | //base case if the row is first then accordingly find the minimum 23 | if (exploreCols < 0 or exploreCols >= mat.size()) return INF; 24 | if (ind == 0) return mat[0][exploreCols]; 25 | if (memo[ind][exploreCols] != -1) return memo[ind][exploreCols]; 26 | //another base case if our index is move out of bound 27 | int upward = mat[ind][exploreCols] + findMinimumPathFallingSumUsingMemo(mat, ind - 1, exploreCols, memo); 28 | int leftDiagonal = mat[ind][exploreCols] + findMinimumPathFallingSumUsingMemo(mat, ind - 1, exploreCols - 1, memo); 29 | int rightDiagonal = mat[ind][exploreCols] + findMinimumPathFallingSumUsingMemo(mat, ind - 1, exploreCols + 1, memo); 30 | return memo[ind][exploreCols] = min({leftDiagonal, upward, rightDiagonal}); 31 | } 32 | 33 | /*Tabulation Approach*/ 34 | int findMinimumPathFallingSumUsingTabu(vector> &mat) { 35 | int n = mat.size(); 36 | vector> memo(n, vector(n, -1)); 37 | //base case , like for the first row the values are remain as same as in mat for the memo 38 | for (int col = 0; col < n; col++) memo[0][col] = mat[0][col]; 39 | // now for the n -1 rows and n cols 40 | for (int row = 1; row < n; row++) { 41 | for (int col = 0; col < n; col++) { 42 | 43 | int upward = mat[row][col] + memo[row - 1][col]; 44 | 45 | int leftDiagonal = mat[row][col] ; 46 | if (col - 1 >= 0)leftDiagonal += memo[row - 1][col - 1]; 47 | else leftDiagonal += (INF); 48 | 49 | int rightDiagonal = mat[row][col] ; 50 | if (col + 1 < n)rightDiagonal += memo[row - 1][col + 1]; 51 | else rightDiagonal += (INF); 52 | 53 | memo[row][col] = min({leftDiagonal, upward, rightDiagonal}); 54 | } 55 | } 56 | 57 | //now in the end we have the maximum sum at every cell in the last row so now we want maximum among all of them for that 58 | int mini = *min_element(memo[n - 1].begin(), memo[n - 1].end()); 59 | return mini; 60 | } 61 | 62 | /*Most optimal approach SPACE OPTIMISATION */ 63 | int mostOptimalMaxFallingPathSum(vector> &mat) { 64 | int n = mat.size(); 65 | vector prev(n); 66 | //base case , like for the first row the values are remain as same as in mat for the memo 67 | for (int col = 0; col < n; col++) prev[col] = mat[0][col]; 68 | // now for the n -1 rows and n cols 69 | for (int row = 1; row < n; row++) { 70 | vector curr(n); 71 | for (int col = 0; col < n; col++) { 72 | int upward = mat[row][col] + prev[col]; 73 | 74 | int leftDiagonal = mat[row][col] ; 75 | if (col - 1 >= 0)leftDiagonal += prev[col - 1]; 76 | else leftDiagonal += (INF); 77 | 78 | int rightDiagonal = mat[row][col] ; 79 | if (col + 1 < n)rightDiagonal += prev[col + 1]; 80 | else rightDiagonal += (INF); 81 | 82 | curr[col] = min({leftDiagonal, upward, rightDiagonal}); 83 | } 84 | prev = curr; 85 | } 86 | 87 | //now in the end we have the maximum sum at every cell in the last row so now we want maximum among all of them for that 88 | int mini = *min_element(prev.begin(), prev.end()); 89 | return mini; 90 | } 91 | 92 | 93 | int minFallingPathSum(vector>& matrix) { 94 | 95 | // In this i start from the last row and move towards the first row 96 | int n = matrix.size(); 97 | int minSum = INT_MAX; 98 | vector> memo(n, vector(n, -1)); 99 | //also we can start from 0 to n-1 100 | 101 | /* for (int col = n - 1; col >= 0; col--) { 102 | //for recursive 103 | // minSum = min(minSum, findMinimumPathFallingSum(matrix, n - 1, col)); 104 | 105 | //for memoisation 106 | // minSum = min(minSum, findMinimumPathFallingSumUsingMemo(matrix, n - 1, col, memo)); 107 | }*/ 108 | 109 | // for tabulation 110 | // minSum = min(minSum, findMinimumPathFallingSumUsingTabu(matrix)); 111 | 112 | //for space optimisation 113 | minSum = min(minSum, mostOptimalMaxFallingPathSum(matrix)); 114 | return minSum; 115 | } 116 | 117 | 118 | 119 | 120 | int main() { 121 | //given the square matrix 122 | int n; 123 | cin >> n; 124 | vector> grid(n, vector (n)); 125 | for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) cin >> grid[i][j]; 126 | cout << minFallingPathSum(grid) << endl; 127 | return 0; 128 | 129 | } -------------------------------------------------------------------------------- /2D - DP on Grid/Minimum Path Sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define INF 1e9;//for adding the at max value in our answer when we reach to out of boundaries so that we cannot take that sum path 5 | 6 | 7 | /*Memoisation approach - TC - O(m*n) and SC = O(path length) */ 8 | 9 | int findMinumumSumUsingMemoisation(int i, int j , vector> &grid, vector> &dp) { 10 | if (i == 0 and j == 0) return grid[0][0]; 11 | if (i < 0 or j < 0) return INF; 12 | //overlapping case 13 | if (dp[i][j] != -1) return dp[i][j]; 14 | int up = grid[i][j] + findMinumumSumUsingMemoisation(i - 1, j, grid, dp) ; 15 | int left = grid[i][j] + findMinumumSumUsingMemoisation(i , j - 1, grid, dp); 16 | return dp[i][j] = min(up, left); 17 | } 18 | 19 | 20 | /*Tabulation approach TC = O(M*N) and SC = O(M*N)*/ 21 | int findMinumumSumUsingTabulation(vector> &grid, vector> &dp) { 22 | int n = grid.size(), m = grid[0].size(); 23 | for (int i = 0; i < n; i++) { 24 | for (int j = 0; j < m; j++) { 25 | //base case 26 | if (i == 0 and j == 0) dp[i][j] = grid[i][j]; 27 | else { 28 | int up = grid[i][j]; 29 | if (i > 0)up += dp[i - 1][j]; 30 | else up += INF;//remember these key points as memoisation these are the base case where if we 31 | // go out of bound then for ignoring that sum upto that point we add the larger value in the upward 32 | int left = grid[i][j]; 33 | if (j > 0)left += dp[i][ j - 1]; 34 | else left += INF;//remember these key points as memoisation these are the base case where if we 35 | // go out of bound then for ignoring that sum upto that point we add the larger value in the leftward 36 | dp[i][j] = min(up, left); 37 | } 38 | } 39 | } 40 | return dp[n - 1][m - 1]; 41 | } 42 | 43 | 44 | int mostOptimalMinPathSum(vector> &grid) { 45 | int n = grid.size(), m = grid[0].size(); 46 | vector prev(m); 47 | for (int i = 0; i < n; i++) { 48 | vector curr(m); 49 | for (int j = 0; j < m; j++) { 50 | //base case 51 | if (i == 0 and j == 0) curr[j] = grid[i][j]; 52 | else { 53 | int up = grid[i][j]; 54 | if (i > 0)up += prev[j]; 55 | else up += INF;//remember these key points as memoisation these are the base case where if we 56 | // go out of bound then for ignoring that sum upto that point we add the larger value in the upward 57 | int left = grid[i][j]; 58 | if (j > 0)left += curr[ j - 1]; 59 | else left += INF;//remember these key points as memoisation these are the base case where if we 60 | // go out of bound then for ignoring that sum upto that point we add the larger value in the leftward 61 | curr[j] = min(up, left); 62 | } 63 | } 64 | prev = curr; 65 | } 66 | return prev[m - 1]; 67 | } 68 | 69 | 70 | int minPathSum(vector>& grid) { 71 | int n = grid.size(), m = grid[0].size(); 72 | vector> dp(n, vector (m, -1)); 73 | //for memoisation 74 | // int ans = findMinumumSumUsingMemoisation(n - 1, m - 1, grid, dp); 75 | 76 | //for tabulation 77 | // int ans = findMinumumSumUsingTabulation(grid, dp); 78 | //for most optimal 79 | int ans = mostOptimalMinPathSum(grid); 80 | return ans; 81 | 82 | } 83 | 84 | 85 | int main() { 86 | int m, n; 87 | cin >> m >> n; 88 | vector> grid(m, vector (n)); 89 | for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) cin >> grid[i][j]; 90 | cout << minPathSum(grid) << endl; 91 | return 0; 92 | 93 | } -------------------------------------------------------------------------------- /2D - DP on Grid/Ninja Training.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //recursive code for the problem -Ninjas Training 5 | int helperToFind(int day, vector> &points, int lastDay) { 6 | //base case 7 | if (day == 0) { 8 | int maxi = 0 ; 9 | for (int i = 0; i < 3; i++)if (i != lastDay)maxi = max(maxi, points[0][i]); 10 | return maxi; 11 | } 12 | int maxi = 0; 13 | for (int i = 0; i < 3; i++) { 14 | if (i != lastDay) { 15 | int activity = points[day][i] + helperToFind(day - 1 , points, i); 16 | maxi = max(maxi, activity); 17 | } 18 | } 19 | return maxi; 20 | } 21 | 22 | 23 | //memoisation code 24 | int helperToFindMemo(int day, vector> &points, int lastDay, vector> &dp) { 25 | //base case 26 | if (dp[day][lastDay] != -1) return dp[day][lastDay]; 27 | if (day == 0) { 28 | int maxi = 0 ; 29 | for (int i = 0; i < 3; i++)if (i != lastDay)maxi = max(maxi, points[0][i]); 30 | return dp[day][lastDay] = maxi; 31 | } 32 | int maxi = 0; 33 | for (int task = 0; task < 3; task++) { 34 | if (task != lastDay) { 35 | int pointAcheive = points[day][task] + helperToFindMemo(day - 1 , points, task, dp);//here this i becomes the last task that was done 36 | maxi = max(maxi, pointAcheive); 37 | } 38 | } 39 | return dp[day][lastDay] = maxi; 40 | } 41 | 42 | 43 | 44 | int helperToFindTabulation(int n, vector> &points) { 45 | vector>dp(n, vector (4, 0));//dp[day][last] 46 | //whatever the base cases fix them in the dp array 47 | dp[0][0] = max(points[0][1], points[0][2]); 48 | dp[0][1] = max(points[0][0], points[0][2]); 49 | dp[0][2] = max(points[0][0], points[0][1]); 50 | dp[0][3] = max({points[0][0], points[0][1], points[0][2]}); 51 | 52 | //now if we fix the base case then in total there will be loop from 1- n-1 53 | for (int day = 1; day < n; day++) { 54 | //for the 4 possible cases i.e., last day task 55 | for (int last = 0; last < 4; last++) { 56 | dp[day][last] = 0; 57 | //for the 3 tasks out of which we have to choose 58 | for (int task = 0; task < 3; task++) { 59 | if (task != last) { 60 | int pointAcheive = points[day][task] + dp[day - 1][task]; 61 | dp[day][last] = max(dp[day][last], pointAcheive); 62 | } 63 | } 64 | } 65 | } 66 | return dp[n - 1][3]; 67 | } 68 | 69 | 70 | //space optimisation 71 | int mostOptimalResult(int n, vector> &points) { 72 | vector prev(4); //dp[day][last] 73 | //whatever the base cases fix them in the dp array 74 | prev[0] = max(points[0][1], points[0][2]); 75 | prev[1] = max(points[0][0], points[0][2]); 76 | prev[2] = max(points[0][0], points[0][1]); 77 | prev[3] = max({points[0][0], points[0][1], points[0][2]}); 78 | 79 | //now if we fix the base case then in total there will be loop from 1- n-1 80 | for (int day = 1; day < n; day++) { 81 | //for the 4 possible cases i.e., last day task 82 | vector temp(4); 83 | for (int last = 0; last < 4; last++) { 84 | temp[last] = 0; 85 | //for the 3 tasks out of which we have to choose 86 | for (int task = 0; task < 3; task++) { 87 | if (task != last) { 88 | int pointAcheive = points[day][task] + prev[task]; 89 | temp[last] = max(temp[last], pointAcheive); 90 | } 91 | } 92 | } 93 | prev = temp;//placing 94 | } 95 | return prev[3]; 96 | } 97 | 98 | 99 | 100 | int ninjaTraining(int n, vector> &points) 101 | { 102 | // int ans = helperToFind(n - 1, points, 3);//for recursion 103 | vector>dp(n, vector (4, -1)); 104 | // int ans = helperToFindMemo(n - 1, points, 3, dp);//for memoisation 105 | // int ans = helperToFindTabulation(n, points); 106 | int ans = mostOptimalResult(n, points); 107 | return ans; 108 | } 109 | 110 | int main() { 111 | int n; 112 | cin >> n; 113 | vector>points(n, vector(3)); 114 | for (int i = 0; i < n; i++)for (int j = 0; j < 3; j++) cin >> points[i][j]; 115 | cout << ninjaTraining(n, points) << "\n"; 116 | return 0; 117 | 118 | } -------------------------------------------------------------------------------- /2D - DP on Grid/Triangle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //memoisation approach 5 | 6 | int findPathSum(int i, int j, vector> &triangle, int n, vector> &dp) { 7 | // there is no out of bound when we reach at the last row automatic return that value 8 | if (i == n - 1) return triangle[i][j]; 9 | if (dp[i][j] != -1) return dp[i][j];//memoise step 10 | int curr = triangle[i][j] + findPathSum(i + 1, j, triangle, n, dp); 11 | int next = triangle[i][j] + findPathSum(i + 1, j + 1, triangle, n, dp); 12 | return dp[i][j] = min(curr, next); 13 | } 14 | 15 | //tabulation approach 16 | int findPathSumTabul(vector> &triangle) { 17 | int n = triangle.size(); 18 | vector> dp(n, vector(n)); 19 | 20 | //base case 21 | for (int j = 0; j < n; j++) dp[n - 1][j] = triangle[n - 1][j]; 22 | 23 | //rest of the code 24 | for (int i = n - 2; i >= 0; i--) { 25 | for (int j = i; j >= 0; j--) { 26 | int curr = triangle[i][j] + dp[i + 1][j]; 27 | int next = triangle[i][j] + dp[i + 1][j + 1]; 28 | dp[i][j] = min(curr, next); 29 | } 30 | } 31 | return dp[0][0]; 32 | } 33 | 34 | // space optimisation approach 35 | int findPathSumSpaceOpt(vector> &triangle) { 36 | int n = triangle.size(); 37 | vector prev(n), curr(n); 38 | 39 | //base case 40 | for (int j = 0; j < n; j++) prev[j] = triangle[n - 1][j]; 41 | 42 | //rest of the code 43 | for (int i = n - 2; i >= 0; i--) { 44 | for (int j = i; j >= 0; j--) { 45 | int cur = triangle[i][j] + prev[j]; 46 | int next = triangle[i][j] + prev[j + 1]; 47 | curr[j] = min(cur, next); 48 | } 49 | prev = curr; 50 | } 51 | return prev[0]; 52 | } 53 | 54 | int minimumTotal(vector>& triangle) { 55 | int n = triangle.size(); 56 | //for memoisation approach 57 | // vector> dp(n, vector(n, -1)); 58 | // int res = findPathSum(0, 0, triangle, n, dp); 59 | 60 | //for tabulation approach 61 | // int res = findPathSumTabul(triangle); 62 | 63 | //for space optimisation approach 64 | int res = findPathSumSpaceOpt(triangle); 65 | 66 | return res; 67 | } 68 | 69 | int main() { 70 | int n; 71 | cin >> n ; 72 | vector> triangle(n); 73 | for (int i = 0 ; i < n; i++) { 74 | vector v(i + 1); 75 | for (int j = 0; j < i + 1; j++) 76 | cin >> v[j]; 77 | triangle[i] = v; 78 | } 79 | cout << minimumTotal(triangle); 80 | return 0; 81 | } -------------------------------------------------------------------------------- /3D - DP on Grid + DP On stocks/Best Time to Buy & sell stocks 3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*---------First method using 3D Dp with all three approaches Memoization , tabulation and space optimisation--------- */ 5 | 6 | // memoization using 3 states ind, buy and total =2 7 | int findMaxProfitIIIMemo(int i, int n, vector &profit, int buy, int prof, vector>> &dp, int total) { 8 | //base case 9 | if (total == 0 or i == n) return 0; 10 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 11 | if (dp[i][buy][total] != -1)return dp[i][buy][total]; 12 | if (buy) 13 | prof = max(-profit[i] + findMaxProfitIIIMemo(i + 1, n, profit, 0, prof, dp, total), findMaxProfitIIIMemo(i + 1, n, profit, 1, prof, dp, total)); 14 | else 15 | prof = max(profit[i] + findMaxProfitIIIMemo(i + 1, n, profit, 1, prof, dp, total - 1), findMaxProfitIIIMemo(i + 1, n, profit, 0, prof, dp, total)); 16 | return dp[i][buy][total] = prof; 17 | } 18 | 19 | 20 | /*tabulation using memoization */ 21 | int findMaxProfitTabulIII(vector &profit) { 22 | int n = profit.size(); 23 | vector>> dp(n + 1, vector> (2, vector (3, 0))); 24 | 25 | //bottom up because in memoization we start from the 0 so here we do invert 26 | for (int i = n - 1; i >= 0; i--) { 27 | for (int buy = 0; buy <= 1; buy++) { 28 | //according to the base case for every total = 0 return 0 29 | for (int total = 1; total <= 2; total++) { 30 | long long prof = 0; 31 | if (buy) { 32 | prof = max(-profit[i] + dp[i + 1][0][total], dp[i + 1][1][total]); 33 | } 34 | else 35 | prof = max(profit[i] + dp[i + 1][1][total - 1], dp[i + 1][0][total]); 36 | dp[i][buy][total] = prof; 37 | } 38 | } 39 | } 40 | return dp[0][1][2]; 41 | 42 | } 43 | 44 | 45 | //space optimisation approach using 2d array from the 3d array 46 | 47 | int findMaxProfitSpaceOptIII(vector &profit) { 48 | int n = profit.size(); 49 | vector> prev(2, vector (3, 0)), curr(2, vector (3, 0)); 50 | 51 | for (int i = n - 1; i >= 0; i--) { 52 | for (int buy = 0; buy <= 1; buy++) { 53 | //according to the base case for every total = 0 return 0 54 | for (int total = 1; total <= 2; total++) { 55 | long long prof = 0; 56 | if (buy) { 57 | prof = max(-profit[i] + prev[0][total], prev[1][total]); 58 | } 59 | else 60 | prof = max(profit[i] + prev[1][total - 1], prev[0][total]); 61 | curr[buy][total] = prof; 62 | } 63 | } 64 | prev = curr; 65 | } 66 | return prev[1][2]; 67 | 68 | } 69 | 70 | 71 | /*-------------Most optimal approach with all three methods - Memoization ,Tabulation and Space optimization-------------*/ 72 | 73 | int giveMaxProfitIII(int i, int n, vector &profit, int transactions , vector> &dp) { 74 | if (i == n or transactions == 4) return 0; 75 | if (dp[i][transactions] != -1) return dp[i][transactions]; 76 | if (transactions % 2 == 0) {//even means we have can buy 77 | dp[i][transactions] = max(-profit[i] + giveMaxProfitIII(i + 1, n, profit, transactions + 1, dp), 78 | giveMaxProfitIII(i + 1, n, profit, transactions, dp)); 79 | 80 | } 81 | else { 82 | dp[i][transactions] = max(profit[i] + giveMaxProfitIII(i + 1, n, profit, transactions + 1, dp), 83 | giveMaxProfitIII(i + 1, n, profit, transactions, dp)); 84 | } 85 | return dp[i][transactions]; 86 | } 87 | 88 | 89 | // for tabulation 90 | int giveMaxProfitIIITabul(vector &profit) { 91 | int n = profit.size(); 92 | vector> dp(n + 1, vector(5, 0)); 93 | //no need to check for base cases because already the values are 0 94 | for (int i = n - 1; i >= 0; i--) { 95 | for (int trans = 0; trans < 4; trans++) { 96 | if (trans % 2 == 0) {//even means we have can buy 97 | dp[i][trans] = max(-profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 98 | } 99 | else { 100 | dp[i][trans] = max(profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 101 | } 102 | } 103 | } 104 | return dp[0][0]; 105 | } 106 | 107 | //space optimisation for above approach 108 | int giveMaxProfitIIISpaceOpt(vector &profit) { 109 | int n = profit.size(); 110 | vector prev (5, 0), curr(5, 0); 111 | //no need to check for base cases because already the values are 0 112 | for (int i = n - 1; i >= 0; i--) { 113 | for (int trans = 0; trans < 4; trans++) { 114 | if (trans % 2 == 0) {//even means we have can buy 115 | curr[trans] = max(-profit[i] + prev[trans + 1], prev[trans]); 116 | } 117 | else { 118 | curr[trans] = max(profit[i] + prev[trans + 1], prev[trans]); 119 | } 120 | } 121 | prev = curr; 122 | } 123 | return prev[0]; 124 | } 125 | 126 | 127 | int maxProfit(vector &profit) { 128 | int n = profit.size(); 129 | 130 | /*-------------------------------For first method-------------------------------*/ 131 | 132 | //for recursion 133 | // int res = findMaxProfit(0, n, profit, 1, 0); 134 | 135 | //for memoization 136 | // vector>> dp(n, vector> (2, vector (3, -1))); 137 | 138 | // int res = findMaxProfitIIIMemo(0, n, profit, true, 0, dp, 2); 139 | 140 | //for tabulation 141 | // int res = findMaxProfitTabulIII(profit); 142 | 143 | //for space optimisation 144 | // int res = findMaxProfitSpaceOptIII(profit); 145 | 146 | 147 | /*-------------------------------For Second method-------------------------------*/ 148 | //for recursion 149 | vector> dp(n + 1, vector(4, -1)); 150 | /*Why 4 ? Since we have to buy at max 2 times which means we have 2 choices for each 151 | 1 - B/S , 2 - B/S , total = 4 152 | 153 | Now for more clarity,the perfect sequence for the transaction is: B S B S 154 | Because, neither we buy two adjacents nor we can sale and also we have to buy first thats'why 155 | So , if we observer then B's are on even index and S's are on odd so which means when transaction 156 | is even we have to buy them otherwise sell it. 157 | Thats It. 158 | 159 | */ 160 | //for memoization 161 | // int res = giveMaxProfitIII(0, n, profit, 0, dp); 162 | //for tabulation 163 | // int res = giveMaxProfitIIITabul(profit); 164 | //for space optimisation 165 | int res = giveMaxProfitIIISpaceOpt(profit); 166 | return res; 167 | 168 | } 169 | 170 | int main() { 171 | int n; 172 | cin >> n; 173 | vector profit(n); 174 | for (int &i : profit) cin >> i; 175 | cout << maxProfit(profit); 176 | return 0; 177 | 178 | } -------------------------------------------------------------------------------- /3D - DP on Grid + DP On stocks/Best Time to Buy & sell stocks 4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*---------First method using 3D Dp with all three approaches Memoization , tabulation and space optimisation--------- */ 5 | 6 | // memoization using 3 states ind, buy and total =2 7 | int findMaxProfitIVMemo(int i, int n, vector &profit, int buy, int prof, vector>> &dp, int total) { 8 | //base case 9 | if (total == 0 or i == n) return 0; 10 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 11 | if (dp[i][buy][total] != -1)return dp[i][buy][total]; 12 | if (buy) 13 | prof = max(-profit[i] + findMaxProfitIVMemo(i + 1, n, profit, 0, prof, dp, total), findMaxProfitIVMemo(i + 1, n, profit, 1, prof, dp, total)); 14 | else 15 | prof = max(profit[i] + findMaxProfitIVMemo(i + 1, n, profit, 1, prof, dp, total - 1), findMaxProfitIVMemo(i + 1, n, profit, 0, prof, dp, total)); 16 | return dp[i][buy][total] = prof; 17 | } 18 | 19 | 20 | /*tabulation using memoization */ 21 | int findMaxProfitTabulIV(vector &profit, int k) { 22 | int n = profit.size(); 23 | vector>> dp(n + 1, vector> (2, vector (k + 1, 0))); 24 | 25 | //bottom up because in memoization we start from the 0 so here we do invert 26 | for (int i = n - 1; i >= 0; i--) { 27 | for (int buy = 0; buy <= 1; buy++) { 28 | //according to the base case for every total = 0 return 0 29 | for (int total = 1; total <= k; total++) { 30 | long long prof = 0; 31 | if (buy) { 32 | prof = max(-profit[i] + dp[i + 1][0][total], dp[i + 1][1][total]); 33 | } 34 | else 35 | prof = max(profit[i] + dp[i + 1][1][total - 1], dp[i + 1][0][total]); 36 | dp[i][buy][total] = prof; 37 | } 38 | } 39 | } 40 | return dp[0][1][k]; 41 | 42 | } 43 | 44 | 45 | //space optimisation approach using 2d array from the 3d array 46 | 47 | int findMaxProfitSpaceOptIV(vector &profit, int k) { 48 | int n = profit.size(); 49 | vector> prev(2, vector (k + 1, 0)), curr(2, vector (k + 1, 0)); 50 | 51 | for (int i = n - 1; i >= 0; i--) { 52 | for (int buy = 0; buy <= 1; buy++) { 53 | //according to the base case for every total = 0 return 0 54 | for (int total = 1; total <= k; total++) { 55 | long long prof = 0; 56 | if (buy) { 57 | prof = max(-profit[i] + prev[0][total], prev[1][total]); 58 | } 59 | else 60 | prof = max(profit[i] + prev[1][total - 1], prev[0][total]); 61 | curr[buy][total] = prof; 62 | } 63 | } 64 | prev = curr; 65 | } 66 | return prev[1][k]; 67 | 68 | } 69 | 70 | /*-------------Most optimal approach with all three methods - Memoization ,Tabulation and Space optimization-------------*/ 71 | 72 | int giveMaxProfitIV(int i, int n, vector &profit, int transactions , vector> &dp, int k) { 73 | if (i == n or transactions == 2 * k) return 0; 74 | if (dp[i][transactions] != -1) return dp[i][transactions]; 75 | if (transactions % 2 == 0) {//even means we have can buy 76 | dp[i][transactions] = max(-profit[i] + giveMaxProfitIV(i + 1, n, profit, transactions + 1, dp, k), 77 | giveMaxProfitIV(i + 1, n, profit, transactions, dp, k)); 78 | 79 | } 80 | else { 81 | dp[i][transactions] = max(profit[i] + giveMaxProfitIV(i + 1, n, profit, transactions + 1, dp, k), 82 | giveMaxProfitIV(i + 1, n, profit, transactions, dp, k)); 83 | } 84 | return dp[i][transactions]; 85 | } 86 | 87 | // for tabulation 88 | int giveMaxProfitIVTabul(vector &profit, int transactions) { 89 | int n = profit.size(); 90 | vector> dp(n + 1, vector(2 * transactions + 1, 0)); 91 | //no need to check for base cases because already the values are 0 92 | for (int i = n - 1; i >= 0; i--) { 93 | for (int trans = 0; trans < 2 * transactions; trans++) { 94 | if (trans % 2 == 0) {//even means we have can buy 95 | dp[i][trans] = max(-profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 96 | } 97 | else { 98 | dp[i][trans] = max(profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 99 | } 100 | } 101 | } 102 | return dp[0][0]; 103 | } 104 | 105 | //space optimisation for above approach 106 | int giveMaxProfitIVSpaceOpt(vector &profit, int transactions) { 107 | int n = profit.size(); 108 | vector prev (2 * transactions + 1, 0), curr(2 * transactions + 1, 0); 109 | //no need to check for base cases because already the values are 0 110 | for (int i = n - 1; i >= 0; i--) { 111 | for (int trans = 0; trans < 2 * transactions; trans++) { 112 | if (trans % 2 == 0) {//even means we have can buy 113 | curr[trans] = max(-profit[i] + prev[trans + 1], prev[trans]); 114 | } 115 | else { 116 | curr[trans] = max(profit[i] + prev[trans + 1], prev[trans]); 117 | } 118 | } 119 | prev = curr; 120 | } 121 | return prev[0]; 122 | } 123 | 124 | 125 | 126 | int maxProfit(vector &profit, int k) { 127 | int n = profit.size(); 128 | 129 | /*-------------------------------For first method-------------------------------*/ 130 | 131 | //for recursion 132 | // int res = findMaxProfit(0, n, profit, 1, 0); 133 | 134 | //for memoization 135 | // vector>> dp(n, vector> (2, vector (k + 1, -1))); 136 | 137 | // int res = findMaxProfitIVMemo(0, n, profit, true, 0, dp, 2); 138 | 139 | //for tabulation 140 | // int res = findMaxProfitTabulIV(profit); 141 | 142 | //for space optimisation 143 | // int res = findMaxProfitSpaceOptIV(profit); 144 | 145 | /*-------------------------------For Second method-------------------------------*/ 146 | //for memoization 147 | 148 | //total combinations are 2*k 149 | // vector> dp(n + 1, vector(2 * k, -1)); 150 | // int res = giveMaxProfitIV(0, n, profit, 0, dp, k); 151 | 152 | //for tabulation 153 | // int res = giveMaxProfitIVTabul(profit, k); 154 | 155 | //for space optimization 156 | int res = giveMaxProfitIVSpaceOpt(profit, k); 157 | 158 | return res; 159 | 160 | } 161 | 162 | int main() { 163 | int n; 164 | cin >> n; 165 | vector profit(n); 166 | for (int &i : profit) cin >> i; 167 | int k; cin >> k; 168 | cout << maxProfit(profit, k); 169 | return 0; 170 | 171 | } -------------------------------------------------------------------------------- /3D - DP on Grid + DP On stocks/Cherry Pickup.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //recursive approach 5 | 6 | int findMaximumChocolates(int currRow, int currColAlice, int currColBob, vector> &grid, int row, int col) { 7 | //base case for the out of boundaries, if both of these guys are moves out of boundaries then return the minimum possible value 8 | if (currColAlice<0 or currColAlice >= col or currColBob<0 or currColBob >= col) return -1e9; 9 | //base case for the destination 10 | if (currRow == row - 1) { 11 | //means they both reached the destination 12 | // if both are at same cell then count that cell at once 13 | if (currColAlice == currColBob) return grid[currRow][currColAlice]; 14 | //else both the cells are counted as different 15 | else return grid[currRow][currColAlice] + grid[currRow][currColBob]; 16 | } 17 | int maxPossibleChocolates = INT_MIN; 18 | //for every curr move of alice , bob has 3 possible moves so in total 3 * 3 moves = 9 moves 19 | for (int aliceMoves = -1 ; aliceMoves <= 1; aliceMoves++) { 20 | for (int bobMoves = -1 ; bobMoves <= 1; bobMoves++) { 21 | //if in somewhere between they both are at the same cell then add it once only 22 | if (currColAlice == currColBob) 23 | maxPossibleChocolates = max(maxPossibleChocolates, grid[currRow][currColAlice] + findMaximumChocolates(currRow + 1, currColAlice + aliceMoves, currColBob + bobMoves, grid, row, col)); 24 | else//add it separately for both , bob and alice 25 | maxPossibleChocolates = max(maxPossibleChocolates, grid[currRow][currColAlice] + grid[currRow][currColBob] + findMaximumChocolates(currRow + 1, currColAlice + aliceMoves, currColBob + bobMoves, grid, row, col)); 26 | } 27 | } 28 | return maxPossibleChocolates; 29 | } 30 | 31 | //Memoisation approach 32 | 33 | int findMaximumChocolatesMemo(int currRow, int currColAlice, int currColBob, vector> &grid, int row, int col, vector>> &memo) { 34 | //base case for the out of boundaries, if both of these guys are moves out of boundaries then return the minimum possible value 35 | if (currColAlice<0 or currColAlice >= col or currColBob<0 or currColBob >= col) return -1e9; 36 | //memoisation code 37 | if (memo[currRow][currColAlice][currColBob] != -1) return memo[currRow][currColAlice][currColBob]; 38 | //base case for the destination 39 | if (currRow == row - 1) { 40 | //means they both reached the destination 41 | // if both are at same cell then count that cell at once 42 | if (currColAlice == currColBob) return grid[currRow][currColAlice]; 43 | //else both the cells are counted as different 44 | else return grid[currRow][currColAlice] + grid[currRow][currColBob]; 45 | } 46 | int maxPossibleChocolates = INT_MIN; 47 | //for every curr move of alice , bob has 3 possible moves so in total 3 * 3 moves = 9 moves 48 | for (int aliceMoves = -1 ; aliceMoves <= 1; aliceMoves++) { 49 | for (int bobMoves = -1 ; bobMoves <= 1; bobMoves++) { 50 | //if in somewhere between they both are at the same cell then add it once only 51 | if (currColAlice == currColBob) 52 | maxPossibleChocolates = max(maxPossibleChocolates, grid[currRow][currColAlice] + findMaximumChocolatesMemo(currRow + 1, currColAlice + aliceMoves, currColBob + bobMoves, grid, row, col, memo)); 53 | else//add it separately for both , bob and alice 54 | maxPossibleChocolates = max(maxPossibleChocolates, grid[currRow][currColAlice] + grid[currRow][currColBob] + findMaximumChocolatesMemo(currRow + 1, currColAlice + aliceMoves, currColBob + bobMoves, grid, row, col, memo)); 55 | } 56 | } 57 | return memo[currRow][currColAlice][currColBob] = maxPossibleChocolates; 58 | } 59 | 60 | 61 | /*Tabulation approach */ 62 | int findMaximumChocolatesTabu(int r, int c , vector> &grid) { 63 | //base case 64 | vector>> memo(r, vector>(c, vector(c, -1))); 65 | for (int alice = 0 ; alice < c; alice++) { 66 | for (int bob = 0; bob < c; bob++) { 67 | //if both are at the same cell in the end then 68 | if (alice == bob)memo[r - 1][alice][bob] = grid[r - 1][bob]; 69 | else memo[r - 1][alice][bob] = grid[r - 1][alice] + grid[r - 1][bob]; 70 | } 71 | } 72 | 73 | //now we set the values for the last row so for the rest of rows (n-2 to 0) 74 | for (int currRow = r - 2; currRow >= 0 ; currRow--) { 75 | for (int aliceCell = 0; aliceCell < c; aliceCell++) { 76 | for (int bobCell = 0; bobCell < c; bobCell++) { 77 | int maxPossibleChocolates = INT_MIN; 78 | //for 9 possibilities 79 | for (int aliceMoves = -1; aliceMoves <= 1; aliceMoves++) { 80 | for (int bobMoves = -1; bobMoves <= 1; bobMoves++) { 81 | int tempValue = 0; 82 | if (aliceCell == bobCell)tempValue = grid[currRow][aliceCell]; 83 | else tempValue = grid[currRow][aliceCell] + grid[currRow][bobCell]; 84 | //check for the overflow cases 85 | if (aliceMoves + aliceCell >= 0 and aliceCell + aliceMoves < c and bobCell + bobMoves >= 0 and bobCell + bobMoves < c) { 86 | tempValue += memo[currRow + 1][aliceCell + aliceMoves][bobCell + bobMoves]; 87 | } 88 | else tempValue += (-1e9); 89 | maxPossibleChocolates = max(maxPossibleChocolates, tempValue); 90 | } 91 | } 92 | memo[currRow][aliceCell][bobCell] = maxPossibleChocolates; 93 | } 94 | } 95 | } 96 | return memo[0][0][c - 1]; 97 | } 98 | 99 | /*Space optimise code using 2- 2D DP arrays instead of using 3D DP */ 100 | int mostOptimalResultUsingSpaceOptimisation(int r, int c, vector> &grid) { 101 | //base case 102 | vector> memo(c, vector(c)), front(c, vector(c)); 103 | for (int alice = 0 ; alice < c; alice++) { 104 | for (int bob = 0; bob < c; bob++) { 105 | //if both are at the same cell in the end then 106 | if (alice == bob)front[alice][bob] = grid[r - 1][bob]; 107 | else front[alice][bob] = grid[r - 1][alice] + grid[r - 1][bob]; 108 | } 109 | } 110 | 111 | //now we set the values for the last row so for the rest of rows (n-2 to 0) 112 | for (int currRow = r - 2; currRow >= 0 ; currRow--) { 113 | for (int aliceCell = 0; aliceCell < c; aliceCell++) { 114 | for (int bobCell = 0; bobCell < c; bobCell++) { 115 | int maxPossibleChocolates = INT_MIN; 116 | //for 9 possibilities 117 | for (int aliceMoves = -1; aliceMoves <= 1; aliceMoves++) { 118 | for (int bobMoves = -1; bobMoves <= 1; bobMoves++) { 119 | int tempValue = 0; 120 | if (aliceCell == bobCell)tempValue = grid[currRow][aliceCell]; 121 | else tempValue = grid[currRow][aliceCell] + grid[currRow][bobCell]; 122 | //check for the overflow cases 123 | if (aliceMoves + aliceCell >= 0 and aliceCell + aliceMoves < c and bobCell + bobMoves >= 0 and bobCell + bobMoves < c) { 124 | tempValue += front[aliceCell + aliceMoves][bobCell + bobMoves]; 125 | } 126 | else tempValue += (-1e9); 127 | maxPossibleChocolates = max(maxPossibleChocolates, tempValue); 128 | } 129 | } 130 | memo[aliceCell][bobCell] = maxPossibleChocolates; 131 | } 132 | } 133 | front = memo; 134 | } 135 | return front[0][c - 1]; 136 | } 137 | 138 | 139 | int maximumChocolates(int r, int c, vector> &grid) { 140 | /* alice is at (0, 0) and bob is at (0, col - 1) both are moving downward simultaneously , which means row remains same 141 | for every point but column will changes so for that we take row as common and columns for both variable so in short 142 | it will done in 3 states which means it will be done using 3-D DP */ 143 | //for recursion 144 | // int ans = findMaximumChocolates(0, 0, c - 1, grid, r, c); 145 | 146 | // vector>> memo(r, vector>(c, vector(c, -1))); 147 | // int ans = findMaximumChocolatesMemo(0, 0, c - 1, grid, r, c, memo); 148 | 149 | //for tabulation 150 | // int ans = findMaximumChocolatesTabu(r, c, grid); 151 | 152 | //for space optimised approach 153 | 154 | int ans = mostOptimalResultUsingSpaceOptimisation(r, c, grid); 155 | return ans; 156 | 157 | } 158 | 159 | int main() { 160 | int row, col; 161 | cin >> row >> col; 162 | vector>grid(row, vector (col)); 163 | for (int i = 0; i < row; i++) for (int j = 0; j < col; j++) cin >> grid[i][j]; 164 | cout << maximumChocolates(row, col, grid); 165 | return 0; 166 | 167 | } -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Largest Divisible Subset(LIS).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | vector largestDivisibleSubset(vector& nums) { 6 | sort(nums.begin(), nums.end()); 7 | int n = nums.size(); 8 | vector dp(n, 1), track(n); 9 | int lastIdx = -1, maxLength = 0; 10 | for (int i = 0 ; i < n; i++) track[i] = i; 11 | for (int i = 0; i < n; i++) { 12 | for (int prev = 0; prev < i; prev++) { 13 | if (nums[i] % nums[prev] == 0 && dp[i] < 1 + dp[prev]) { 14 | dp[i] = max(dp[i], 1 + dp[prev]); 15 | track[i] = prev; 16 | } 17 | } 18 | if (dp[i] > maxLength) { 19 | maxLength = dp[i]; 20 | lastIdx = i; 21 | } 22 | } 23 | vector lis(maxLength); 24 | lis[maxLength - 1] = nums[lastIdx]; 25 | if (maxLength < 2) return lis; 26 | for (int i = maxLength - 2; i >= 0; i--) { 27 | lis[i] = nums[track[lastIdx]]; 28 | lastIdx = track[lastIdx]; 29 | } 30 | return lis; 31 | } 32 | 33 | int main() { 34 | 35 | int n; cin >> n; 36 | vector arr(n); 37 | for (int &i : arr) cin >> i; 38 | vector res = largestDivisibleSubset(arr); 39 | for (int i : res) cout << i << " "; 40 | return 0; 41 | 42 | } -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Longest Bitonic Subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int longestBitonicSequence(vector& arr, int n) { 5 | vector leftToRight(n, 1), rightToLeft(n, 1); 6 | int maxLength = 0; 7 | 8 | /*finding lis from left to right*/ 9 | for (int i = 0; i < n; i++) { 10 | for (int prev = 0; prev < i; prev++) { 11 | if (arr[i] > arr[prev] && leftToRight[i] < 1 + leftToRight[prev]) {//another condition is for preventing it to change afterward if somewhere the value is same 12 | leftToRight[i] = max(leftToRight[i], 1 + leftToRight[prev]); 13 | } 14 | } 15 | } 16 | 17 | /*finding lis from right to left*/ 18 | for (int i = n - 1; i >= 0; i--) { 19 | for (int prev = n - 1; prev > i; prev--) { 20 | if (arr[i] > arr[prev] && rightToLeft[i] < 1 + rightToLeft[prev]) {//another condition is for preventing it to change afterward if somewhere the value is same 21 | rightToLeft[i] = max(rightToLeft[i], 1 + rightToLeft[prev]); 22 | } 23 | } 24 | //now find the bitonic subsequence length using first and second and in both the index for 25 | // which we are calculating is counted twice so for checking the Length of Bitonic LIS first reduce - 1 26 | maxLength = max(maxLength, leftToRight[i] + rightToLeft[i] - 1); 27 | 28 | } 29 | return maxLength; 30 | } 31 | 32 | 33 | int main() { 34 | 35 | int n; cin >> n; 36 | vector arr(n); 37 | for (int &i : arr) cin >> i; 38 | cout << longestBitonicSequence(arr, n); 39 | return 0; 40 | 41 | } -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Longest Increasing Subsequence(LIS)-Binary Search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int lengthOfLISusingBinarySearch(vector &nums) { 5 | vector lis; 6 | int n = nums.size(); 7 | lis.push_back(nums[0]); 8 | for (int i = 1; i < n; i++ ) { 9 | if (nums[i] > lis.back()) { 10 | lis.push_back(nums[i]); 11 | } 12 | else { 13 | int idx = lower_bound(lis.begin(), lis.end(), nums[i]) - lis.begin(); 14 | lis[idx] = nums[i]; 15 | } 16 | } 17 | return lis.size(); 18 | } 19 | 20 | int main() { 21 | int n; 22 | cin >> n; 23 | vectorseq(n); 24 | for (int &i : seq) cin >> i; 25 | cout << "Length of LIS : " << lengthOfLISusingBinarySearch(seq); 26 | return 0; 27 | 28 | } -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Longest Increasing Subsequence(LIS).cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | /* Recursive approach - TLE */ 6 | int maxLengthRecur(vector& nums, int ind, int prevInd) { 7 | if (ind == nums.size()) return 0; 8 | int notPick = maxLengthRecur(nums, ind + 1, prevInd); 9 | int pick = 0 ; 10 | if (prevInd == -1 or nums[ind] > nums[prevInd]) pick = 1 + maxLengthRecur(nums, ind + 1, ind); 11 | return max(notPick, pick); 12 | } 13 | 14 | /* Memoization approach */ 15 | int maxLengthMemo(vector& nums, int ind, int prevInd, vector>&dp) { 16 | if (ind == nums.size()) return 0; 17 | /*since prev ==-1 for a time and we know that we can't represent the negative values in the array 18 | so for that we have to shift it one index towards 0 so that -1 is treated as 0 and vice versa...*/ 19 | 20 | if (dp[ind][prevInd + 1] != -1) return dp[ind][prevInd + 1]; 21 | 22 | //picking and not picking way - 23 | int notPick = maxLengthMemo(nums, ind + 1, prevInd, dp); 24 | int pick = 0 ; 25 | if (prevInd == -1 or nums[ind] > nums[prevInd]) pick = 1 + maxLengthMemo(nums, ind + 1, ind, dp); 26 | return dp[ind][prevInd + 1] = max(notPick, pick); 27 | } 28 | 29 | /*tabulation approach */ 30 | int maxLengthTabul(vector &nums) { 31 | int n = nums.size(); 32 | vector> dp(n + 1, vector (n + 1, 0)); 33 | 34 | for (int ind = n - 1; ind >= 0; ind--) { 35 | /*since the prevInd is the previous value of current index so start it from ind - 1 and go till -1 */ 36 | for (int prevInd = ind - 1; prevInd >= -1; prevInd--) { 37 | int notPick = dp[ind + 1][prevInd + 1];//shift all previous states by 1 38 | int pick = 0; 39 | if (prevInd == -1 or nums[ind] > nums[prevInd]) pick = 1 + dp[ind + 1][ind + 1];//shift all previous states by 1 40 | dp[ind][prevInd + 1] = max(notPick, pick); 41 | } 42 | } 43 | return dp[0][0]; 44 | } 45 | 46 | 47 | /*space optimization approach */ 48 | int maxLengthSpaceOpt(vector &nums) { 49 | int n = nums.size(); 50 | vector prevRow(n + 1, 0), currRow(n + 1, 0); 51 | 52 | for (int ind = n - 1; ind >= 0; ind--) { 53 | for (int prevInd = ind - 1; prevInd >= -1; prevInd--) { 54 | int notPick = prevRow[prevInd + 1];//shift all previous states by 1 55 | int pick = 0; 56 | if (prevInd == -1 or nums[ind] > nums[prevInd]) pick = 1 + prevRow[ind + 1];//shift all previous states by 1 57 | currRow[prevInd + 1] = max(notPick, pick); 58 | } 59 | prevRow = currRow; 60 | } 61 | return prevRow[0]; 62 | } 63 | 64 | 65 | 66 | int lengthOfLIS(vector& nums) { 67 | int n = nums.size(); 68 | /* here - 1 is the previous indexed value which is used to 69 | check whether the subsequence we are generating is increasing or decreasing*/ 70 | 71 | //for recursion 72 | // int res = maxLengthRecur(nums, 0, -1); 73 | 74 | 75 | //for memoization 76 | // vector> dp(n, vector (n + 1, -1)); 77 | // int res = maxLengthMemo(nums, 0, -1, dp); 78 | 79 | //for tabulation 80 | // int res = maxLengthTabul(nums); 81 | 82 | // for space optimisation 83 | int res = maxLengthSpaceOpt(nums); 84 | 85 | 86 | return res; 87 | } 88 | 89 | 90 | int main() { 91 | int n; 92 | cin >> n; 93 | vectorseq(n); 94 | for (int &i : seq) cin >> i; 95 | cout << lengthOfLIS(seq); 96 | return 0; 97 | 98 | } -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Longest String chain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | bool lengthWise(string &s1, string &s2) { 5 | return s1.size() < s2.size(); 6 | } 7 | 8 | bool checkPattern(string &currWord, string &prevWord) { 9 | //since for moving forward the size of prevWord has to be +1 equals to the currWord otherwise return false 10 | if (prevWord.size() + 1 != currWord.size()) return false; 11 | int currPtr = 0, prevPtr = 0; 12 | //since the currWord is greater 13 | while (currPtr < currWord.size()) { 14 | if (prevPtr < prevWord.size() and currWord[currPtr] == prevWord[prevPtr]) currPtr++, prevPtr++; 15 | else currPtr++;/* since currWord is the larger one so obviously it has greater number of 16 | characters so if somehow any character is not matched then we have to move the currPtr only*/ 17 | } 18 | //now if both the pointers are at the end then the chain pattern is correct otherwise not 19 | return (currPtr == currWord.size() and prevPtr == prevWord.size()); 20 | } 21 | 22 | int longestStrChain(vector& words) { 23 | int n = words.size(); 24 | sort(words.begin(), words.end(), lengthWise);//sorting because we need the subset since some of the words are also occured previously which we need for further chain 25 | vector dp(n, 1); 26 | int lastIdx = -1, maxLength = 0; 27 | for (int i = 0; i < n; i++) { 28 | for (int prev = 0; prev < i; prev++) { 29 | if (checkPattern(words[i], words[prev]) && dp[i] < 1 + dp[prev]) {//another condition is for preventing it to change afterward if somewhere the value is same 30 | dp[i] = max(dp[i], 1 + dp[prev]); 31 | } 32 | } 33 | maxLength = max(maxLength, dp[i]); 34 | } 35 | return maxLength; 36 | } 37 | 38 | 39 | 40 | int main() { 41 | int n; 42 | cin >> n; 43 | vector words(n); 44 | for (string &i : words) cin >> i; 45 | cout << longestStrChain(words); 46 | return 0; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Number of Longest Increasing Subsequences.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | int findNumberOfLIS(vector& nums) { 6 | int n = nums.size(); 7 | vector dp(n, 1), curr(n, 1); 8 | int maxLength = 0; 9 | for (int i = 0; i < n; i++) { 10 | for (int prev = 0; prev < i; prev++) { 11 | if (nums[i] > nums[prev] && dp[i] < 1 + dp[prev]) {//another condition is for preventing it to change afterward if somewhere the value is same 12 | dp[i] = max(dp[i], 1 + dp[prev]); 13 | curr[i] = curr[prev]; 14 | } 15 | else if (nums[i] > nums[prev] && dp[i] == 1 + dp[prev]) curr[i] += curr[prev]; 16 | } 17 | maxLength = max(maxLength, dp[i]); 18 | } 19 | 20 | /* for (int i : dp) cout << i << " "; 21 | cout << endl; 22 | for (int i : curr) cout << i << " "; 23 | cout << endl; 24 | */ 25 | int totalCount = 0; 26 | for (int i = 0 ; i < n; i++) { 27 | if (dp[i] == maxLength) totalCount += curr[i]; 28 | } 29 | return totalCount; 30 | } 31 | 32 | int main() { 33 | int n; cin >> n; 34 | vector arr(n); 35 | for (int &i : arr) cin >> i; 36 | cout << findNumberOfLIS(arr); 37 | return 0; 38 | 39 | } -------------------------------------------------------------------------------- /DP On Increasing Subsequences/Printing the Longest Increasing Subsequence(LIS).cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 4 | ------------------------------- Link - https://bit.ly/3AVDO1H------------------------------- */ 5 | 6 | #include 7 | using namespace std; 8 | 9 | /*1D dp solution for Finding the length of Longest Increasing Subsequence */ 10 | int lengthOfLIS(vector &nums) { 11 | int n = nums.size(); 12 | vector dp(n, 1); 13 | int maxLength = 0; 14 | //now iterate over all indices with the prev from [0,i-1] 15 | for (int i = 0; i < n; i++) { 16 | for (int prev = 0; prev < i; prev++) { 17 | if (nums[i] > nums[prev]) 18 | dp[i] = max(dp[i], 1 + dp[prev]); 19 | } 20 | maxLength = max(maxLength, dp[i]); 21 | } 22 | return maxLength; 23 | } 24 | 25 | 26 | /*now the above code is used for printing the LIS in O(N^2) 27 | Basically we take a different hash array which keep track of changes in the dp array like whenever the 28 | length is changed from prev then we keep the index because of which the value get changed 29 | */ 30 | vector printLIS(vector &nums) { 31 | int n = nums.size(); 32 | vector dp(n, 1), track(n); 33 | int lastIdx = -1, maxLength = 0; 34 | for (int i = 0 ; i < n; i++) track[i] = i;//fill it with the indices 35 | for (int i = 0; i < n; i++) { 36 | for (int prev = 0; prev < i; prev++) { 37 | if (nums[i] > nums[prev] && dp[i] < 1 + dp[prev]) {//another condition is for preventing it to change afterward if somewhere the value is same 38 | dp[i] = max(dp[i], 1 + dp[prev]); 39 | track[i] = prev; 40 | } 41 | } 42 | if (dp[i] > maxLength) { 43 | maxLength = dp[i];//it keeps the max length of LIS in the dp array 44 | lastIdx = i;//it keeps the index where we go from the dp to the hash array 45 | } 46 | } 47 | //find the maximum in the dp array then get the value at that index then move to same index in the hash array then move 48 | //index of index in the hash array 49 | vector lis(maxLength); 50 | lis[maxLength - 1] = nums[lastIdx]; //this is the last value of the LIS(i.e., greatest one) 51 | if (maxLength < 2) return lis; 52 | for (int i = maxLength - 2; i >= 0; i--) { 53 | lis[i] = nums[track[lastIdx]]; 54 | lastIdx = track[lastIdx]; 55 | } 56 | return lis; 57 | } 58 | 59 | int main() { 60 | int n; cin >> n; 61 | vector nums(n); 62 | for (int &i : nums) cin >> i; 63 | // cout << lengthOfLIS(nums); 64 | vector res = printLIS(nums); 65 | cout << "Longest Increasing Subsequence : "; 66 | for (int i : res) cout << i << " "; 67 | return 0; 68 | 69 | } -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Boolean Evaluation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | const int mod = 1e9 + 7; 5 | 6 | /*memoisation code*/ 7 | 8 | long long findWays(int i, int j, int isTrue, string &exp, vector>>&dp) { 9 | //base cases 10 | if (i > j) return 0; 11 | if (i == j) { 12 | if (isTrue) return exp[i] == 'T'; 13 | else return exp[i] == 'F'; 14 | } 15 | if (dp[i][j][isTrue] != -1) return dp[i][j][isTrue]; 16 | //rest of the logic 17 | long long ways = 0; 18 | for (int ind = i + 1; ind <= j - 1; ind += 2) { 19 | int leftTrue = findWays(i, ind - 1, 1, exp, dp); 20 | int leftFalse = findWays(i, ind - 1, 0, exp, dp); 21 | int rightTrue = findWays(ind + 1, j, 1, exp, dp); 22 | int rightFalse = findWays(ind + 1, j, 0, exp, dp); 23 | //if the operator is & 24 | if (exp[ind] == '&') { 25 | if (isTrue) ways = (ways + (leftTrue * rightTrue) % mod) % mod; 26 | else ways = (ways + (leftTrue * rightFalse) % mod + (leftFalse * rightTrue) % mod + (leftFalse * rightFalse) % mod) % mod; 27 | } 28 | //if the operator is | 29 | if (exp[ind] == '|') { 30 | if (isTrue) ways = (ways + (leftTrue * rightTrue) % mod + (leftTrue * rightFalse) % mod + (leftFalse * rightTrue) % mod) % mod ; 31 | else ways = (ways + (leftFalse * rightFalse) % mod) % mod; 32 | } 33 | //if the operator is ^ 34 | if (exp[ind] == '^') { 35 | if (isTrue) ways = (ways + (leftTrue * rightFalse ) % mod + (leftFalse * rightTrue ) % mod) % mod; 36 | else ways = (ways + (leftTrue * rightTrue) % mod + (leftFalse * rightFalse) % mod) % mod; 37 | } 38 | } 39 | return dp[i][j][isTrue] = ways; 40 | } 41 | 42 | 43 | /*tabulation code */ 44 | int findWaysTabul(int n, string &exp) { 45 | vector>> dp(n , vector>(n , vector(2, -1))); 46 | for (int i = 0; i < n; i++) { 47 | dp[i][i][1] = exp[i] == 'T'; 48 | dp[i][i][0] = exp[i] == 'F'; 49 | } 50 | 51 | //rest of all stuff 52 | for (int i = n - 1; i >= 0; i--) { 53 | for (int j = 0; j < n; j++) { 54 | for (int isTrue = 0; isTrue <= 1; isTrue++) { 55 | if (i == j) continue; 56 | if (i > j) dp[i][j][isTrue] = 0; 57 | long long ways = 0; 58 | for (int ind = i + 1; ind <= j - 1; ind += 2) { 59 | int leftTrue = dp[i][ind - 1][ 1]; 60 | int leftFalse = dp[i][ ind - 1][ 0]; 61 | int rightTrue = dp[ind + 1][ j][ 1]; 62 | 63 | int rightFalse = dp[ind + 1][ j][ 0]; 64 | //if the operator is & 65 | if (exp[ind] == '&') { 66 | if (isTrue) ways = (ways + (leftTrue * rightTrue) % mod) % mod; 67 | else ways = (ways + (leftTrue * rightFalse) % mod + (leftFalse * rightTrue) % mod + (leftFalse * rightFalse) % mod) % mod; 68 | } 69 | //if the operator is | 70 | if (exp[ind] == '|') { 71 | if (isTrue) ways = (ways + (leftTrue * rightTrue) % mod + (leftTrue * rightFalse) % mod + (leftFalse * rightTrue) % mod) % mod ; 72 | else ways = (ways + (leftFalse * rightFalse) % mod) % mod; 73 | } 74 | //if the operator is ^ 75 | if (exp[ind] == '^') { 76 | if (isTrue) ways = (ways + (leftTrue * rightFalse ) % mod + (leftFalse * rightTrue ) % mod) % mod; 77 | else ways = (ways + (leftTrue * rightTrue) % mod + (leftFalse * rightFalse) % mod) % mod; 78 | } 79 | } 80 | dp[i][j][isTrue] = ways % mod; 81 | } 82 | } 83 | } 84 | return dp[0][n - 1][1]; 85 | } 86 | 87 | 88 | int countWays(int n, string exp) { 89 | 90 | /*memoisation code*/ 91 | vector>> dp(n , vector>(n , vector(2, -1))); 92 | int isTrue = 1; 93 | // int res = findWays(0, n - 1, 1, exp, dp); 94 | 95 | 96 | //tabulation code 97 | int res = findWaysTabul(n, exp); 98 | return res; 99 | } 100 | 101 | int main() { 102 | string expression; 103 | cin >> expression; 104 | cout << countWays(expression.size(), expression); 105 | return 0; 106 | 107 | } 108 | -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Burst Balloons.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*memoization approach */ 5 | 6 | int findMaxCoins(int i, int j, vector&balloons, vector> &dp) { 7 | if (i > j) return 0; 8 | if (dp[i][j] != -1) return dp[i][j]; 9 | int maxCoins = 0; 10 | for (int ind = i; ind <= j; ind++) { 11 | int cost = balloons[i - 1] * balloons[ind] * balloons[j + 1] 12 | + findMaxCoins(i, ind - 1, balloons, dp) 13 | + findMaxCoins(ind + 1, j, balloons, dp); 14 | maxCoins = max(cost, maxCoins); 15 | } 16 | return dp[i][j] = maxCoins; 17 | } 18 | 19 | 20 | /*Tabulation approach */ 21 | int findMaxCoinsTabul(vector& balloons) { 22 | //it don't works if we start bursting because the cost depends on the other partitions as well so think in reverse like instead of finding the balloon which burst first think in the way which bursts at last because the last one do not depends on any one (1,1) 23 | int n = balloons.size(); 24 | balloons.insert(balloons.begin(), 1); 25 | balloons.push_back(1); 26 | vector> dp(n + 2, vector(n + 2, 0)); 27 | for (int i = n; i > 0; i--) { 28 | for (int j = 1; j <= n; j++) { 29 | int maxCoins = 0; 30 | if (i > j) continue; 31 | for (int ind = i; ind <= j; ind++) { 32 | int cost = balloons[i - 1] * balloons[ind] * balloons[j + 1] + dp[i][ind - 1] + dp[ind + 1][j]; 33 | maxCoins = max(maxCoins, cost); 34 | } 35 | dp[i][j] = maxCoins; 36 | } 37 | } 38 | return dp[1][n]; 39 | } 40 | 41 | int maxCoins(vector& balloons) { 42 | //it don't works if we start bursting because the cost depends on the other partitions as well so think in reverse like instead of finding the balloon which burst first think in the way which bursts at last because the last one do not depends on any one (1,1) 43 | int n = balloons.size(); 44 | balloons.insert(balloons.begin(), 1); 45 | balloons.push_back(1); 46 | 47 | 48 | //for memoization approach 49 | // vector> dp(n + 1, vector(n + 1, -1)); 50 | // int res = findMaxCoins(1, n, balloons, dp); 51 | // for tabulation approach 52 | int res = findMaxCoinsTabul(balloons); 53 | return res; 54 | } 55 | 56 | int main() { 57 | int numberOfBalloons; 58 | cin >> numberOfBalloons; 59 | vector balloons(numberOfBalloons); 60 | for (int &i : balloons) cin >> i; 61 | cout << maxCoins(balloons); 62 | return 0; 63 | 64 | } 65 | -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Count square submatrices with all 1s.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int numSubmat(vector>& mat) { 5 | int n = mat.size(), m = mat[0].size(); 6 | vector> dp(n, vector (m, 0)); 7 | //base case fixed the values for the first row and coloumns 8 | for (int i = 0; i < n; i++) dp[i][0] = mat[i][0]; 9 | for (int j = 0; j < m; j++) dp[0][j] = mat[0][j]; 10 | //now iterate over all remaining rows and columns 11 | for (int i = 1; i < n; i++) { 12 | for (int j = 1; j < m; j++) { 13 | if (mat[i][j] == 0) dp[i][j] = 0; 14 | else dp[i][j] = 1 + min({dp[i][j - 1], dp[i - 1][j - 1], dp[i - 1][j]}); 15 | } 16 | } 17 | //find the total submatrices 18 | int totalSubmat = 0; 19 | for (int i = 0; i < n; i++) 20 | for (int j = 0; j < m; j++) 21 | totalSubmat += dp[i][j]; 22 | 23 | return totalSubmat; 24 | 25 | } 26 | 27 | 28 | int main() { 29 | int n, m; cin >> n >> m; 30 | vector> grid(n, vector (m)); 31 | for (int i = 0; i < n; i++) { 32 | for (int j = 0; j < m; j++) 33 | cin >> grid[i][j]; 34 | } 35 | cout << numSubmat(grid); 36 | return 0; 37 | 38 | } -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Matrix Chain Multiplication Memoization.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*Recursive code for the MCM - */ 5 | int calculateOperations(int i, int j, vector &arr) { 6 | if (i == j) return 0; 7 | //iterate to check over all indices to create a partition from that index 8 | int minOperations = 1e9; 9 | for (int k = i; k < j; k++) { 10 | int totalSteps = (long long)(arr[i - 1] * arr[k] * arr[j]) 11 | + calculateOperations(i, k, arr) + 12 | calculateOperations(k + 1, j, arr); 13 | minOperations = min(minOperations, totalSteps); 14 | } 15 | return minOperations; 16 | } 17 | 18 | /*memoization code using 2D dp*/ 19 | int calculateOperationsMemo(int i, int j, vector &arr, vector> &dp) { 20 | if (i == j) return 0; 21 | //iterate to check over all indices to create a partition from that index 22 | if (dp[i][j] != -1) return dp[i][j]; 23 | int minOperations = 1e9; 24 | for (int k = i; k < j; k++) { 25 | int totalSteps = (long long)(arr[i - 1] * arr[k] * arr[j]) 26 | + calculateOperationsMemo(i, k, arr, dp) + 27 | calculateOperationsMemo(k + 1, j, arr, dp); 28 | minOperations = min(minOperations, totalSteps); 29 | } 30 | return dp[i][j] = minOperations; 31 | } 32 | 33 | 34 | int matrixChainMultiplication(vector&arr) { 35 | int n = arr.size(); 36 | //for recursion 37 | // int res = calculateOperations(1, n - 1, arr); 38 | 39 | //for memoization 40 | vector> dp(n, vector(n, -1)); 41 | int res = calculateOperationsMemo(1, n - 1, arr, dp); 42 | return res; 43 | } 44 | 45 | 46 | int main() { 47 | int n; 48 | cin >> n; 49 | vectorarr(n); 50 | for (int &i : arr) cin >> i; 51 | cout << matrixChainMultiplication(arr); 52 | return 0; 53 | 54 | } -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Matrix Chain Multiplication Tabulation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*tabulation code*/ 5 | int matrixChainMultiplication(vector&arr) { 6 | int n = arr.size(); 7 | vector> dp(n, vector(n, 0)); 8 | //base case 9 | for (int i = 0; i < n; i++)dp[i][i] = 0; 10 | 11 | for (int i = n - 1; i > 0; i--) { 12 | for (int j = i + 1; j < n; j++) { 13 | /*as the i is always in left of j so if we start j from 1 it recalculates 14 | some area again so for ignoring it start from i+1 everytime*/ 15 | int minOperations = 1e9; 16 | for (int k = i; k < j; k++) { 17 | int totalSteps = (arr[i - 1] * arr[k] * arr[j]) + dp[i][k] + dp[k + 1][j]; 18 | minOperations = min(totalSteps, minOperations); 19 | } 20 | dp[i][j] = minOperations; 21 | } 22 | } 23 | return dp[1][n - 1]; 24 | } 25 | 26 | 27 | int main() { 28 | int n; 29 | cin >> n; 30 | vectorarr(n); 31 | for (int &i : arr) cin >> i; 32 | cout << matrixChainMultiplication(arr); 33 | return 0; 34 | 35 | 36 | } -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Maximum rectangle area with all 1s.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | //this is the code of finding the area of largest rectangle in the histogram in one pass 6 | int giveMaxAreaInRectangle(vector &bars) { 7 | int n = bars.size(), largestArea = INT_MIN; 8 | stack st; 9 | for (int i = 0 ; i <= n; i++) { 10 | while (!st.empty() and (i == n or bars[st.top()] >= bars[i])) { 11 | int height = bars[st.top()], width = 1; 12 | st.pop(); 13 | if (st.empty()) width = i; 14 | else width = i - 1 - st.top(); 15 | height *= width; 16 | largestArea = max(largestArea, height); 17 | } 18 | st.push(i); 19 | } 20 | return largestArea; 21 | } 22 | 23 | 24 | //this is the main code which is used to find the maxarea of the binary matrix 25 | int maximalRectangle(vector>& matrix) { 26 | int n = matrix.size(), m = matrix[0].size(); 27 | vector heights(m); 28 | int maxArea = 0; 29 | for (int i = 0; i < n; i++) { 30 | for (int j = 0; j < m; j++) { 31 | if (matrix[i][j] == '1') heights[j]++; 32 | else heights[j] = 0; 33 | } 34 | //till now we have all possible histograms of each cell 35 | int area = giveMaxAreaInRectangle(heights); 36 | maxArea = max(area, maxArea); 37 | } 38 | return maxArea; 39 | } 40 | 41 | 42 | int main() { 43 | int n, m; 44 | cin >> n >> m; 45 | vector> matrix(n, vector (m)); 46 | for (int i = 0; i < n; i ++) 47 | for (int j = 0; j < m; j++) 48 | cin >> matrix[i][j]; 49 | cout << maximalRectangle(matrix); 50 | return 0; 51 | 52 | } -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Minimum cost to cut the Stick.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //memoisation code 5 | long giveCost(int i, int j, vector&cuts, vector> &dp) { 6 | if (i > j) return 0; 7 | if (dp[i][j] != -1) return dp[i][j]; 8 | long miniCost = INT_MAX; 9 | for (int k = i; k <= j; k++) { 10 | long cost = cuts[j + 1] - cuts[i - 1] + giveCost(i, k - 1, cuts, dp) + giveCost(k + 1, j, cuts, dp); 11 | miniCost = min(miniCost, cost); 12 | } 13 | return dp[i][j] = miniCost; 14 | } 15 | 16 | //tabulation code 17 | long giveCostTabul(int m, vector &cuts) { 18 | vector> dp(m + 2, vector (m + 2, 0)); 19 | for (int i = m; i > 0; i--) { 20 | for (int j = 1; j <= m; j++) { 21 | if (i > j) continue; 22 | long miniCost = (int)INT_MAX; 23 | for (int ind = i; ind <= j; ind++) { 24 | long cost = cuts[j + 1] - cuts[i - 1] + dp[i][ind - 1] + dp[ind + 1][j]; 25 | miniCost = min(miniCost, cost); 26 | } 27 | dp[i][j] = miniCost; 28 | } 29 | } 30 | return dp[1][m]; 31 | } 32 | 33 | 34 | //main code 35 | int minCost(int n, vector& cuts) { 36 | int m = cuts.size(); 37 | cuts.insert(cuts.begin(), 0);//insert the 0 at starting 38 | cuts.push_back(n); 39 | sort(begin(cuts), end(cuts)); 40 | 41 | // for memoisation 42 | // vector> dp(m + 1, vector (m + 1, -1)); 43 | // int res = giveCost(1, m, cuts, dp); 44 | 45 | 46 | //for tabulation 47 | int res = giveCostTabul(m, cuts); 48 | return res; 49 | } 50 | 51 | 52 | int main() { 53 | int n ; cin >> n; 54 | int len; cin >> len; //total length of stick 55 | vector cuts(n); 56 | for (int &i : cuts)cin >> i; 57 | cout << minCost(len, cuts); 58 | return 0; 59 | 60 | } -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Palindrome Partition.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | bool isPalindrome(string &str) { 5 | int n = str.size(), i = 0; 6 | while (i <= n / 2) { 7 | if (str[i] != str[n - i - 1]) 8 | return false; 9 | i++; 10 | } 11 | return true; 12 | } 13 | 14 | // memoisation code 15 | int doPartitions(int ind, string &s, vector&dp) { 16 | //base case 17 | if (ind == s.size()) return 0; 18 | if (dp[ind] != -1) return dp[ind]; 19 | int minCost = INT_MAX; 20 | string substr; 21 | for (int j = ind; j < s.size(); j++) { 22 | substr += s[j]; 23 | if (isPalindrome(substr)) { 24 | int cost = 1 + doPartitions(j + 1, s, dp); 25 | minCost = min(cost, minCost); 26 | } 27 | } 28 | return dp[ind] = minCost;; 29 | 30 | } 31 | 32 | // tabulation code 33 | int doPartitionsTabul(string &s) { 34 | int n = s.size(); 35 | vector dp(n + 1 , 0);//why n+1 because the base case in memo is i==n so for that we have to add dp[n]=0 so take +1 size 36 | for (int ind = n - 1; ind >= 0; ind--) { 37 | int minCost = INT_MAX; 38 | string substr; 39 | for (int j = ind; j < s.size(); j++) { 40 | substr += s[j]; 41 | if (isPalindrome(substr)) { 42 | int cost = 1 + dp[j + 1]; 43 | minCost = min(cost, minCost); 44 | } 45 | dp[ind] = minCost; 46 | } 47 | } 48 | return dp[0] - 1; 49 | } 50 | 51 | 52 | //main function 53 | int minCut(string s) { 54 | int n = s.size(); 55 | /*for memoisation code */ 56 | vector dp(n, -1); 57 | // int res = doPartitions(0, s, dp) - 1;//as we are also adding the last partition which is at the end of string so for removing that do -1. 58 | /*for tabulation*/ 59 | int res = doPartitionsTabul(s); 60 | return res; 61 | } 62 | 63 | 64 | 65 | int main() { 66 | 67 | string s; 68 | cin >> s; 69 | cout << minCut(s); 70 | return 0; 71 | 72 | } 73 | 74 | 75 | class Solution { 76 | int solve(int i, int j , vector> &grid, vector> &dp) { 77 | if (i == 0 and j == 0) return grid[0][0]; 78 | if (i < 0 or j < 0) return -1e9; 79 | if (dp[i][j] != -1) return dp[i][j]; 80 | int up = grid[i][j] + solve(i - 1, j, grid, dp) ; 81 | int left = grid[i][j] + solve(i , j - 1, grid, dp); 82 | return dp[i][j] = max(up, left); 83 | } 84 | int collectMaximumCoins(vector>& mat) { 85 | int n = mat.size(), m = mat[0].size(); 86 | vector> dp(n, vector (m, -1)); 87 | return solve(n - 1, m - 1, mat, dp); 88 | } 89 | }; 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /DP On Partitions(MCM) Pattern/Partition array for Maximum sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //memoisation approach 5 | int doPartitions(int ind, vector &arr, int k, vector &dp) { 6 | int n = arr.size(); 7 | //base case 8 | if (ind == n) return 0; 9 | if (dp[ind] != -1) return dp[ind]; 10 | //main stuff 11 | int lenOfSubarr = 1, maxValue = INT_MIN, maxi = INT_MIN/*for storing the max value for each subarray*/; 12 | for (int j = ind; j < min(n, ind + k); j++) { 13 | maxi = max(maxi, arr[j]); 14 | int cost = (lenOfSubarr++ * maxi) + doPartitions(j + 1, arr, k, dp); 15 | maxValue = max(cost, maxValue); 16 | } 17 | return dp[ind] = maxValue; 18 | } 19 | 20 | //Tabulation approach 21 | int doPartitionsTabul(vector &arr, int k) { 22 | int n = arr.size(); 23 | vector dp(n + 1, 0); 24 | for (int ind = n - 1; ind >= 0; ind--) { 25 | int lenOfSubarr = 1, maxValue = INT_MIN, maxi = INT_MIN/*for storing the max value for each subarray*/; 26 | for (int j = ind; j < min(n, ind + k); j++) { 27 | maxi = max(maxi, arr[j]); 28 | int cost = (lenOfSubarr++ * maxi) + dp[j + 1]; 29 | maxValue = max(cost, maxValue); 30 | } 31 | dp[ind] = maxValue; 32 | } 33 | return dp[0]; 34 | } 35 | 36 | //main problem function 37 | int maxSumAfterPartitioning(vector& arr, int k) { 38 | int n = arr.size(); 39 | //memoisation code 40 | // vector dp(n, -1); 41 | // int res = doPartitions(0, arr, k, dp); 42 | 43 | //tabulation code 44 | int res = doPartitionsTabul(arr, k); 45 | return res; 46 | } 47 | 48 | int main() { 49 | int n; 50 | cin >> n; 51 | vector arr(n); 52 | for (int &i : arr) cin >> i; 53 | int k; cin >> k; 54 | cout << maxSumAfterPartitioning(arr, k); 55 | return 0; 56 | 57 | } -------------------------------------------------------------------------------- /DP on Stocks/Best Time to Buy & Sell stock with Cooldown.cpp: -------------------------------------------------------------------------------- 1 | /*In this problem if we sell the item then we cannot buy on consecutive day so solution is remain similat to the 2 | Buy and sell stock 2 just replace the i + 1 by i + 2 when we sell something and change the base case from i ==n to i>=n becuase 3 | of two jumps somewhere the index goes beyond the n that's why .................*/ 4 | 5 | #include 6 | using namespace std; 7 | 8 | // memoization using 2 states ind, and buy 9 | int findMaxProfitCooldown(int i, int n, vector &profit, int buy, int prof, vector> &dp) { 10 | //base case 11 | if (i >= n) return 0; 12 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 13 | if (dp[i][buy] != -1)return dp[i][buy]; 14 | if (buy) 15 | prof = max(-profit[i] + findMaxProfitCooldown(i + 1, n, profit, 0, prof, dp), findMaxProfitCooldown(i + 1, n, profit, 1, prof, dp)); 16 | else 17 | prof = max(profit[i] + findMaxProfitCooldown(i + 2, n, profit, 1, prof, dp), findMaxProfitCooldown(i + 1, n, profit, 0, prof, dp)); 18 | return dp[i][buy] = prof; 19 | } 20 | 21 | /*tabulation using memoization */ 22 | int findMaxProfitCooldownTabul(vector &profit) { 23 | int n = profit.size(); 24 | vector> dp(n + 2, vector (2, 0));//2 because sometimes we gonna jump 2 times because of that sometimes we go beyond the n 25 | dp[n][0] = dp[n][1] = 0;//no need to add this base although 26 | 27 | //bottom up because in memoization we start from the 0 so here we do invert 28 | for (int i = n - 1; i >= 0; i--) { 29 | dp[i][1] = max(-profit[i] + dp[i + 1][0], dp[i + 1][1]); 30 | dp[i][0] = max(profit[i] + dp[i + 2][1], dp[i + 1][0]); 31 | cout << dp[i][1] << ", " << dp[i][1] << endl; 32 | } 33 | return dp[0][1]; 34 | } 35 | 36 | 37 | /* space optimisation - We can space optimise it but because as we do i + 2 which means we also need prev of prev because of 38 | that we have to maintain 3 arrays for getting the i + 2 so this is the solution for that */ 39 | 40 | int findMaxProfitCooldownSpaceOpt(vector &profit) { 41 | int n = profit.size(); 42 | vector prev(2, 0), prevOfprev(2, 0), curr(2, 0); 43 | //size 2 because sometimes we gonna jump 2 times because of that sometimes we go beyond the n and arrays 3 because of i+2 44 | 45 | //bottom up because in memoization we start from the 0 so here we do invert 46 | for (int i = n - 1; i >= 0; i--) { 47 | curr[1] = max(-profit[i] + prev[0], prev[1]); 48 | curr[0] = max(profit[i] + prevOfprev[1], prev[0]); 49 | prevOfprev = prev; 50 | prev = curr; 51 | } 52 | return prev[1]; 53 | } 54 | 55 | 56 | 57 | int maxProfit(vector &profit) { 58 | int n = profit.size(); 59 | //for memoization 60 | // vector> dp(n, vector (2, -1)); 61 | // int res = findMaxProfitCooldown(0, n, profit, 1, 0, dp); 62 | 63 | //for tabulation 64 | int res = findMaxProfitCooldownTabul(profit); 65 | 66 | //for space optimisation 67 | // int res = findMaxProfitCooldownSpaceOpt(profit); 68 | return res; 69 | 70 | } 71 | 72 | 73 | int main() { 74 | int n; 75 | cin >> n; 76 | vector profit(n); 77 | for (int &i : profit) cin >> i; 78 | cout << maxProfit(profit); 79 | return 0; 80 | 81 | } 82 | 83 | /*Note : 84 | - We can omit the inner buy loop because whenever the buy is 1 then only that buy function called else the sell 85 | function called so by removing it just place the buy[0] for the buy and buy[1] for the sell. 86 | 87 | */ -------------------------------------------------------------------------------- /DP on Stocks/Best Time to Buy & Sell stocks with Transaction Fees.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*This is the tabulation method only we can also use memoization and space optimisation For the same problem */ 5 | 6 | int findMaxProfitCooldownSpaceOpt(vector &profit, int fees) { 7 | int n = profit.size(); 8 | vector> dp(n + 1, vector (2, 0)); 9 | 10 | for (int i = n - 1; i >= 0; i--) { 11 | for (int buy = 0; buy <= 1; buy++) { 12 | long long prof = 0; 13 | if (buy) { 14 | prof = max(-profit[i] + dp[i + 1][0], dp[i + 1][1]); 15 | } 16 | else { 17 | prof = max(profit[i] - fees + dp[i + 1][1], dp[i + 1][0]); 18 | //so when we sell something after buying which means we have done one transaction 19 | //so after getting total profit substract the fees from that 20 | 21 | } 22 | dp[i][buy] = prof; 23 | } 24 | } 25 | return dp[0][1]; 26 | } 27 | 28 | 29 | 30 | int maxProfit(vector &profit, int fees) { 31 | int n = profit.size(); 32 | int res = findMaxProfitCooldownSpaceOpt(profit, fees); 33 | return res; 34 | 35 | } 36 | 37 | 38 | int main() { 39 | int n; 40 | cin >> n; 41 | vector profit(n); 42 | for (int &i : profit) cin >> i; 43 | int fees; cin >> fees; 44 | cout << maxProfit(profit, fees); 45 | return 0; 46 | 47 | } -------------------------------------------------------------------------------- /DP on Stocks/Best Time to Buy & sell stocks 2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //recursive 5 | int findMaxProfit(int i, int n, vector &profit, int buy, int prof) { 6 | //base case 7 | if (i == n) return 0; 8 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 9 | if (buy) 10 | prof = max(-profit[i] + findMaxProfit(i + 1, n, profit, 0, prof), findMaxProfit(i + 1, n, profit, 1, prof)); 11 | else 12 | prof = max(profit[i] + findMaxProfit(i + 1, n, profit, 1, prof), findMaxProfit(i + 1, n, profit, 0, prof)); 13 | return prof; 14 | } 15 | 16 | // memoization using 2states ind, and buy 17 | int findMaxProfitMemo(int i, int n, vector &profit, int buy, int prof, vector> &dp) { 18 | //base case 19 | if (i == n) return 0; 20 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 21 | if (dp[i][buy] != -1)return dp[i][buy]; 22 | if (buy) 23 | prof = max(-profit[i] + findMaxProfitMemo(i + 1, n, profit, 0, prof, dp), findMaxProfitMemo(i + 1, n, profit, 1, prof, dp)); 24 | else 25 | prof = max(profit[i] + findMaxProfitMemo(i + 1, n, profit, 1, prof, dp), findMaxProfitMemo(i + 1, n, profit, 0, prof, dp)); 26 | 27 | return dp[i][buy] = prof; 28 | } 29 | 30 | /*tabulation using memoization */ 31 | int findMaxProfitTabul(vector &profit) { 32 | int n = profit.size(); 33 | vector> dp(n + 1, vector (2, -1)); 34 | dp[n][0] = dp[n][1] = 0; 35 | 36 | //bottom up because in memoization we start from the 0 so here we do invert 37 | for (int i = n - 1; i >= 0; i--) { 38 | for (int buy = 0; buy <= 1; buy++) { 39 | long long prof = 0; 40 | if (buy) { 41 | prof = max(-profit[i] + dp[i + 1][0], dp[i + 1][1]); 42 | } 43 | else { 44 | prof = max(profit[i] + dp[i + 1][1], dp[i + 1][0]); 45 | 46 | } 47 | dp[i][buy] = prof; 48 | } 49 | } 50 | return dp[0][1]; 51 | 52 | } 53 | 54 | 55 | //space optimisation approach using 1d array 56 | 57 | int findMaxProfitSpaceOpt(vector &profit) { 58 | int n = profit.size(); 59 | vector prev (2), curr(2);//prev is the next column because we are moving from last to first 60 | prev[0] = prev[1] = 0; 61 | 62 | //bottom up because in memoization we start from the 0 so here we do invert 63 | for (int i = n - 1; i >= 0; i--) { 64 | for (int buy = 0; buy <= 1; buy++) { 65 | long long prof = 0; 66 | if (buy) { 67 | prof = max(-profit[i] + prev[0], prev[1]); 68 | } 69 | else { 70 | prof = max(profit[i] + prev[1], prev[0]); 71 | 72 | } 73 | curr[buy] = prof; 74 | } 75 | prev = curr; 76 | } 77 | return prev[1]; 78 | 79 | } 80 | 81 | // Use variables instead of these 2 arrays 82 | int findMaxProfitUsingVariables(vector &profit) { 83 | int n = profit.size(); 84 | long long currNotBuy , currBuy, prevNotBuy , prevBuy; 85 | prevBuy = prevNotBuy = 0; 86 | 87 | //bottom up because in memoization we start from the 0 so here we do inve rt 88 | for (int i = n - 1; i >= 0; i--) { 89 | currBuy = max(-profit[i] + prevNotBuy, prevBuy); 90 | currNotBuy = max(profit[i] + prevBuy, prevNotBuy); 91 | prevBuy = currBuy; 92 | prevNotBuy = currNotBuy; 93 | } 94 | return prevBuy; 95 | 96 | } 97 | 98 | int maxProfit(vector &profit) { 99 | int n = profit.size(); 100 | //for recursion 101 | // int res = findMaxProfit(0, n, profit, 1, 0); 102 | //for memoization 103 | vector> dp(n, vector (2, -1)); 104 | int res = findMaxProfitMemo(0, n, profit, true, 0, dp); 105 | 106 | //for tabulation 107 | // int res = findMaxProfitTabul(profit); 108 | 109 | //for space optimisation 110 | // int res = findMaxProfitSpaceOpt(profit); 111 | 112 | //for most optimal solution - using variables 113 | // int res = findMaxProfitUsingVariables(profit); 114 | 115 | return res; 116 | 117 | } 118 | 119 | int main() { 120 | int n; 121 | cin >> n; 122 | vector profit(n); 123 | for (int &i : profit) cin >> i; 124 | cout << maxProfit(profit); 125 | return 0; 126 | 127 | } 128 | 129 | /*Note : 130 | - We can omit the inner buy loop because whenever the buy is 1 then only that buy function called else the sell 131 | function called so by removing it just place the buy[0] for the buy and buy[1] for the sell. 132 | 133 | */ -------------------------------------------------------------------------------- /DP on Stocks/Best Time to Buy & sell stocks 3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*---------First method using 3D Dp with all three approaches Memoization , tabulation and space optimisation--------- */ 5 | 6 | // memoization using 3 states ind, buy and total =2 7 | int findMaxProfitIIIMemo(int i, int n, vector &profit, int buy, int prof, vector>> &dp, int total) { 8 | //base case 9 | if (total == 0 or i == n) return 0; 10 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 11 | if (dp[i][buy][total] != -1)return dp[i][buy][total]; 12 | if (buy) 13 | prof = max(-profit[i] + findMaxProfitIIIMemo(i + 1, n, profit, 0, prof, dp, total), findMaxProfitIIIMemo(i + 1, n, profit, 1, prof, dp, total)); 14 | else 15 | prof = max(profit[i] + findMaxProfitIIIMemo(i + 1, n, profit, 1, prof, dp, total - 1), findMaxProfitIIIMemo(i + 1, n, profit, 0, prof, dp, total)); 16 | return dp[i][buy][total] = prof; 17 | } 18 | 19 | 20 | /*tabulation using memoization */ 21 | int findMaxProfitTabulIII(vector &profit) { 22 | int n = profit.size(); 23 | vector>> dp(n + 1, vector> (2, vector (3, 0))); 24 | 25 | //bottom up because in memoization we start from the 0 so here we do invert 26 | for (int i = n - 1; i >= 0; i--) { 27 | for (int buy = 0; buy <= 1; buy++) { 28 | //according to the base case for every total = 0 return 0 29 | for (int total = 1; total <= 2; total++) { 30 | long long prof = 0; 31 | if (buy) { 32 | prof = max(-profit[i] + dp[i + 1][0][total], dp[i + 1][1][total]); 33 | } 34 | else 35 | prof = max(profit[i] + dp[i + 1][1][total - 1], dp[i + 1][0][total]); 36 | dp[i][buy][total] = prof; 37 | } 38 | } 39 | } 40 | return dp[0][1][2]; 41 | 42 | } 43 | 44 | 45 | //space optimisation approach using 2d array from the 3d array 46 | 47 | int findMaxProfitSpaceOptIII(vector &profit) { 48 | int n = profit.size(); 49 | vector> prev(2, vector (3, 0)), curr(2, vector (3, 0)); 50 | 51 | for (int i = n - 1; i >= 0; i--) { 52 | for (int buy = 0; buy <= 1; buy++) { 53 | //according to the base case for every total = 0 return 0 54 | for (int total = 1; total <= 2; total++) { 55 | long long prof = 0; 56 | if (buy) { 57 | prof = max(-profit[i] + prev[0][total], prev[1][total]); 58 | } 59 | else 60 | prof = max(profit[i] + prev[1][total - 1], prev[0][total]); 61 | curr[buy][total] = prof; 62 | } 63 | } 64 | prev = curr; 65 | } 66 | return prev[1][2]; 67 | 68 | } 69 | 70 | 71 | /*-------------Most optimal approach with all three methods - Memoization ,Tabulation and Space optimization-------------*/ 72 | 73 | int giveMaxProfitIII(int i, int n, vector &profit, int transactions , vector> &dp) { 74 | if (i == n or transactions == 4) return 0; 75 | if (dp[i][transactions] != -1) return dp[i][transactions]; 76 | if (transactions % 2 == 0) {//even means we have can buy 77 | dp[i][transactions] = max(-profit[i] + giveMaxProfitIII(i + 1, n, profit, transactions + 1, dp), 78 | giveMaxProfitIII(i + 1, n, profit, transactions, dp)); 79 | 80 | } 81 | else { 82 | dp[i][transactions] = max(profit[i] + giveMaxProfitIII(i + 1, n, profit, transactions + 1, dp), 83 | giveMaxProfitIII(i + 1, n, profit, transactions, dp)); 84 | } 85 | return dp[i][transactions]; 86 | } 87 | 88 | 89 | // for tabulation 90 | int giveMaxProfitIIITabul(vector &profit) { 91 | int n = profit.size(); 92 | vector> dp(n + 1, vector(5, 0)); 93 | //no need to check for base cases because already the values are 0 94 | for (int i = n - 1; i >= 0; i--) { 95 | for (int trans = 0; trans < 4; trans++) { 96 | if (trans % 2 == 0) {//even means we have can buy 97 | dp[i][trans] = max(-profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 98 | } 99 | else { 100 | dp[i][trans] = max(profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 101 | } 102 | } 103 | } 104 | return dp[0][0]; 105 | } 106 | 107 | //space optimisation for above approach 108 | int giveMaxProfitIIISpaceOpt(vector &profit) { 109 | int n = profit.size(); 110 | vector prev (5, 0), curr(5, 0); 111 | //no need to check for base cases because already the values are 0 112 | for (int i = n - 1; i >= 0; i--) { 113 | for (int trans = 0; trans < 4; trans++) { 114 | if (trans % 2 == 0) {//even means we have can buy 115 | curr[trans] = max(-profit[i] + prev[trans + 1], prev[trans]); 116 | } 117 | else { 118 | curr[trans] = max(profit[i] + prev[trans + 1], prev[trans]); 119 | } 120 | } 121 | prev = curr; 122 | } 123 | return prev[0]; 124 | } 125 | 126 | 127 | int maxProfit(vector &profit) { 128 | int n = profit.size(); 129 | 130 | /*-------------------------------For first method-------------------------------*/ 131 | 132 | //for recursion 133 | // int res = findMaxProfit(0, n, profit, 1, 0); 134 | 135 | //for memoization 136 | // vector>> dp(n, vector> (2, vector (3, -1))); 137 | 138 | // int res = findMaxProfitIIIMemo(0, n, profit, true, 0, dp, 2); 139 | 140 | //for tabulation 141 | // int res = findMaxProfitTabulIII(profit); 142 | 143 | //for space optimisation 144 | // int res = findMaxProfitSpaceOptIII(profit); 145 | 146 | 147 | /*-------------------------------For Second method-------------------------------*/ 148 | //for recursion 149 | vector> dp(n + 1, vector(4, -1)); 150 | /*Why 4 ? Since we have to buy at max 2 times which means we have 2 choices for each 151 | 1 - B/S , 2 - B/S , total = 4 152 | 153 | Now for more clarity,the perfect sequence for the transaction is: B S B S 154 | Because, neither we buy two adjacents nor we can sale and also we have to buy first thats'why 155 | So , if we observer then B's are on even index and S's are on odd so which means when transaction 156 | is even we have to buy them otherwise sell it. 157 | Thats It. 158 | 159 | */ 160 | //for memoization 161 | // int res = giveMaxProfitIII(0, n, profit, 0, dp); 162 | //for tabulation 163 | // int res = giveMaxProfitIIITabul(profit); 164 | //for space optimisation 165 | int res = giveMaxProfitIIISpaceOpt(profit); 166 | return res; 167 | 168 | } 169 | 170 | int main() { 171 | int n; 172 | cin >> n; 173 | vector profit(n); 174 | for (int &i : profit) cin >> i; 175 | cout << maxProfit(profit); 176 | return 0; 177 | 178 | } -------------------------------------------------------------------------------- /DP on Stocks/Best Time to Buy & sell stocks 4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*---------First method using 3D Dp with all three approaches Memoization , tabulation and space optimisation--------- */ 5 | 6 | // memoization using 3 states ind, buy and total =2 7 | int findMaxProfitIVMemo(int i, int n, vector &profit, int buy, int prof, vector>> &dp, int total) { 8 | //base case 9 | if (total == 0 or i == n) return 0; 10 | //if ww buy something, 1 is for active buy - means we can buy now and 0 is for inactive like we cannot buy for the next 11 | if (dp[i][buy][total] != -1)return dp[i][buy][total]; 12 | if (buy) 13 | prof = max(-profit[i] + findMaxProfitIVMemo(i + 1, n, profit, 0, prof, dp, total), findMaxProfitIVMemo(i + 1, n, profit, 1, prof, dp, total)); 14 | else 15 | prof = max(profit[i] + findMaxProfitIVMemo(i + 1, n, profit, 1, prof, dp, total - 1), findMaxProfitIVMemo(i + 1, n, profit, 0, prof, dp, total)); 16 | return dp[i][buy][total] = prof; 17 | } 18 | 19 | 20 | /*tabulation using memoization */ 21 | int findMaxProfitTabulIV(vector &profit, int k) { 22 | int n = profit.size(); 23 | vector>> dp(n + 1, vector> (2, vector (k + 1, 0))); 24 | 25 | //bottom up because in memoization we start from the 0 so here we do invert 26 | for (int i = n - 1; i >= 0; i--) { 27 | for (int buy = 0; buy <= 1; buy++) { 28 | //according to the base case for every total = 0 return 0 29 | for (int total = 1; total <= k; total++) { 30 | long long prof = 0; 31 | if (buy) { 32 | prof = max(-profit[i] + dp[i + 1][0][total], dp[i + 1][1][total]); 33 | } 34 | else 35 | prof = max(profit[i] + dp[i + 1][1][total - 1], dp[i + 1][0][total]); 36 | dp[i][buy][total] = prof; 37 | } 38 | } 39 | } 40 | return dp[0][1][k]; 41 | 42 | } 43 | 44 | 45 | //space optimisation approach using 2d array from the 3d array 46 | 47 | int findMaxProfitSpaceOptIV(vector &profit, int k) { 48 | int n = profit.size(); 49 | vector> prev(2, vector (k + 1, 0)), curr(2, vector (k + 1, 0)); 50 | 51 | for (int i = n - 1; i >= 0; i--) { 52 | for (int buy = 0; buy <= 1; buy++) { 53 | //according to the base case for every total = 0 return 0 54 | for (int total = 1; total <= k; total++) { 55 | long long prof = 0; 56 | if (buy) { 57 | prof = max(-profit[i] + prev[0][total], prev[1][total]); 58 | } 59 | else 60 | prof = max(profit[i] + prev[1][total - 1], prev[0][total]); 61 | curr[buy][total] = prof; 62 | } 63 | } 64 | prev = curr; 65 | } 66 | return prev[1][k]; 67 | 68 | } 69 | 70 | /*-------------Most optimal approach with all three methods - Memoization ,Tabulation and Space optimization-------------*/ 71 | 72 | int giveMaxProfitIV(int i, int n, vector &profit, int transactions , vector> &dp, int k) { 73 | if (i == n or transactions == 2 * k) return 0; 74 | if (dp[i][transactions] != -1) return dp[i][transactions]; 75 | if (transactions % 2 == 0) {//even means we have can buy 76 | dp[i][transactions] = max(-profit[i] + giveMaxProfitIV(i + 1, n, profit, transactions + 1, dp, k), 77 | giveMaxProfitIV(i + 1, n, profit, transactions, dp, k)); 78 | 79 | } 80 | else { 81 | dp[i][transactions] = max(profit[i] + giveMaxProfitIV(i + 1, n, profit, transactions + 1, dp, k), 82 | giveMaxProfitIV(i + 1, n, profit, transactions, dp, k)); 83 | } 84 | return dp[i][transactions]; 85 | } 86 | 87 | // for tabulation 88 | int giveMaxProfitIVTabul(vector &profit, int transactions) { 89 | int n = profit.size(); 90 | vector> dp(n + 1, vector(2 * transactions + 1, 0)); 91 | //no need to check for base cases because already the values are 0 92 | for (int i = n - 1; i >= 0; i--) { 93 | for (int trans = 0; trans < 2 * transactions; trans++) { 94 | if (trans % 2 == 0) {//even means we have can buy 95 | dp[i][trans] = max(-profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 96 | } 97 | else { 98 | dp[i][trans] = max(profit[i] + dp[i + 1][trans + 1], dp[i + 1][trans]); 99 | } 100 | } 101 | } 102 | return dp[0][0]; 103 | } 104 | 105 | //space optimisation for above approach 106 | int giveMaxProfitIVSpaceOpt(vector &profit, int transactions) { 107 | int n = profit.size(); 108 | vector prev (2 * transactions + 1, 0), curr(2 * transactions + 1, 0); 109 | //no need to check for base cases because already the values are 0 110 | for (int i = n - 1; i >= 0; i--) { 111 | for (int trans = 0; trans < 2 * transactions; trans++) { 112 | if (trans % 2 == 0) {//even means we have can buy 113 | curr[trans] = max(-profit[i] + prev[trans + 1], prev[trans]); 114 | } 115 | else { 116 | curr[trans] = max(profit[i] + prev[trans + 1], prev[trans]); 117 | } 118 | } 119 | prev = curr; 120 | } 121 | return prev[0]; 122 | } 123 | 124 | 125 | 126 | int maxProfit(vector &profit, int k) { 127 | int n = profit.size(); 128 | 129 | /*-------------------------------For first method-------------------------------*/ 130 | 131 | //for recursion 132 | // int res = findMaxProfit(0, n, profit, 1, 0); 133 | 134 | //for memoization 135 | // vector>> dp(n, vector> (2, vector (k + 1, -1))); 136 | 137 | // int res = findMaxProfitIVMemo(0, n, profit, true, 0, dp, 2); 138 | 139 | //for tabulation 140 | // int res = findMaxProfitTabulIV(profit); 141 | 142 | //for space optimisation 143 | // int res = findMaxProfitSpaceOptIV(profit); 144 | 145 | /*-------------------------------For Second method-------------------------------*/ 146 | //for memoization 147 | 148 | //total combinations are 2*k 149 | // vector> dp(n + 1, vector(2 * k, -1)); 150 | // int res = giveMaxProfitIV(0, n, profit, 0, dp, k); 151 | 152 | //for tabulation 153 | // int res = giveMaxProfitIVTabul(profit, k); 154 | 155 | //for space optimization 156 | int res = giveMaxProfitIVSpaceOpt(profit, k); 157 | 158 | return res; 159 | 160 | } 161 | 162 | int main() { 163 | int n; 164 | cin >> n; 165 | vector profit(n); 166 | for (int &i : profit) cin >> i; 167 | int k; cin >> k; 168 | cout << maxProfit(profit, k); 169 | return 0; 170 | 171 | } -------------------------------------------------------------------------------- /DP on Stocks/Best Time to Buy & sell stocks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int maxProfit(vector& prices) { 5 | int n = prices.size(); 6 | int buyAt = prices[0], profitOf = 0; 7 | for (int i = 1 ; i < n; i++) { 8 | int cost = prices[i] - buyAt; //total profit or loss 9 | profitOf = max(profitOf, cost); 10 | buyAt = min(buyAt, prices[i]); 11 | } 12 | return profitOf; 13 | } 14 | 15 | int main() { 16 | int days; 17 | cin >> days; 18 | vector prices(days); 19 | for (int &pricePerDay : prices) cin >> pricePerDay; 20 | cout << maxProfit(prices); 21 | return 0; 22 | } 23 | 24 | //singhkunal01bu -------------------------------------------------------------------------------- /DP on Strings/Distinct Subsequences.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | /*Recursive + Memoization code */ 6 | 7 | int countDistinctNumberWays(int i, int j, string &mainStr, string &target, vector> &dp) { 8 | //base cases 9 | //if we reached at the index below 0 for the target which means we have check full string i.e.,so 10 | if (j < 0) return 1; 11 | /*for shifting replace above line with j==0*/ 12 | 13 | //if we reached at the index below 0 for the mainStr which means we haven't check full string i.e.,target so 14 | if (i < 0) return 0; 15 | /*for shifting replace above line with i==0*/ 16 | 17 | if (dp[i][j] != -1) return dp[i][j]; 18 | 19 | //now if the both characters are same then 20 | 21 | if (mainStr[i] == target[j]) { 22 | /*for shifting replace above line with mainStr[i-1] == target[j-1]*/ 23 | 24 | /*there would be two cases if we want to add that character in our resultant sequence then or 25 | we want the same character at any different place (index) then -*/ 26 | return dp[i][j] = countDistinctNumberWays(i - 1, j - 1, mainStr, target, dp) + 27 | countDistinctNumberWays(i - 1, j, mainStr, target, dp);/*this second one is for checking diff. index 28 | for the same characeer .*/ 29 | 30 | } 31 | //if both the characters donot matched then stay on the same jth index and check the character in the mainStr 32 | return dp[i][j] = countDistinctNumberWays(i - 1, j, mainStr, target, dp); 33 | 34 | } 35 | 36 | 37 | /*Tabulation approach for the same */ 38 | int countDistinctNumberWaysTabul(string &mainStr, string &target) { 39 | int n = mainStr.size(), m = target.size(); 40 | vector> dp(n + 1, vector(m + 1)); 41 | 42 | //because of < 0 of bases because of it we can't represent negatives in array so as like LCS we gonna shift 43 | for (int i = 0; i <= n; i++)dp[i][0] = 1;//for the first test case 44 | // for (int j = 1; j <= m; j++)dp[0][j] = 0; //we can ommit this because by default the values are 0 filled 45 | 46 | for (int i = 1; i <= n; i++) { 47 | for (int j = 1; j <= m; j++) { 48 | if (mainStr[i - 1] == target[j - 1]) { 49 | dp[i][j] = dp[i - 1][ j - 1] + dp[i - 1][j]; 50 | } 51 | else dp[i][j] = dp[i - 1][j]; 52 | } 53 | } 54 | return (int)dp[n][m]; 55 | /*for larger cases make sure to remove int and place double or unsigned int */ 56 | } 57 | 58 | /*space optimisatio approach for the same - 2 ARRAYS*/ 59 | int countDistinctNumberWaysSpaceOptimised(string &mainStr, string &target) { 60 | int n = mainStr.size(), m = target.size(); 61 | vector prev(m + 1), curr(m + 1); 62 | prev[0] = curr[0] = 1;//for the first test case 63 | for (int i = 1; i <= n; i++) { 64 | for (int j = 1; j <= m; j++) { 65 | if (mainStr[i - 1] == target[j - 1]) { 66 | curr[j] = prev[j - 1] + prev[j]; 67 | } 68 | else curr[j] = prev[j]; 69 | } 70 | prev = curr; 71 | } 72 | return (int)prev[m]; 73 | } 74 | /*space optimisatio approach for the same - 1 ARRAY*/ 75 | int countDistinctNumberWaysSpaceOptimised_SingleArray(string &mainStr, string &target) { 76 | int n = mainStr.size(), m = target.size(); 77 | vector prev(m + 1); 78 | prev[0] = 1; //for the first test case 79 | for (int i = 1; i <= n; i++) { 80 | for (int j = m; j > 0; j--) { 81 | if (mainStr[i - 1] == target[j - 1]) { 82 | prev[j] = prev[j - 1] + prev[j]; 83 | } 84 | else prev[j] = prev[j]; 85 | } 86 | } 87 | return (int)prev[m]; 88 | } 89 | 90 | 91 | int numDistinct(string &mainStr, string &target) { 92 | int n = mainStr.size(), m = target.size(); 93 | 94 | //for memoization 95 | // vector> dp(n, vector (m, -1)); 96 | /*for shifting replace above line with vector> dp(n+1, vector (m+1, -1))*/ 97 | // int totalWays = countDistinctNumberWays(n - 1, m - 1, mainStr, target, dp); 98 | 99 | 100 | // for tabulation 101 | // int totalWays = countDistinctNumberWaysTabul(mainStr, target); 102 | 103 | //for space optimised approach 104 | // int totalWays = countDistinctNumberWaysSpaceOptimised(mainStr, target); 105 | 106 | //for single array space optimisation 107 | int totalWays = countDistinctNumberWaysSpaceOptimised_SingleArray(mainStr, target); 108 | 109 | return totalWays; 110 | } 111 | 112 | int main() { 113 | string mainStr, target; 114 | cin >> mainStr >> target; 115 | cout << numDistinct(mainStr, target); 116 | return 0; 117 | 118 | } -------------------------------------------------------------------------------- /DP on Strings/Edit Distance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | /*recursive + memoization code*/ 6 | int findMinimumOperations(int i, int j, string &mainStr, string &target, vector> &dp) { 7 | //base cases are quite tricky like when we exhausted either of the string 8 | //if we exhausted the first string then wherever the jth pointer we have that much characters remaining to traverse so 9 | if (i == 0) return j; 10 | //if we exhausted the second string then wherever the ith pointer we have that much characters remaining to get converted so 11 | if (j == 0) return i; 12 | 13 | //memoization base case 14 | if (dp[i][j] != -1) return dp[i][j]; 15 | //now if both the characters are matched then 16 | if (mainStr[i - 1] == target[j - 1]) return dp[i][j] = findMinimumOperations(i - 1, j - 1, mainStr, target, dp); 17 | //else we have to do three operations for insertion , for deletion & for replacement 18 | return dp[i][j] = min({1 + findMinimumOperations(i, j - 1, mainStr, target, dp),/*for insertion if we hypothetically insert the character to get matched 19 | then obviously our ith pointer remains same because we add the character at the last of mainStr and now hypothetically both the characters are 20 | matched so we gonna move out jth pointer*/ 21 | 1 + findMinimumOperations(i - 1, j, mainStr, target, dp), /*now for deletion means we don't want that character from mainStr so 22 | just to skip that move our ith Pointer and stay on jth to compare it with upcoming character*/ 23 | 1 + findMinimumOperations(i - 1, j - 1, mainStr, target, dp)/*for replacement means we replaced the current ith Character hypothetically 24 | and we gonna move further that is after replacement the characters got matched so move both pointers*/ 25 | }); 26 | 27 | } 28 | 29 | /*tabulation approach - Now we saw that we have the bases where pointer goes < 0 so we need to shift the indices 30 | for that we have to check (mainStr[i-1] == target[j-1]) instead of (mainStr[i] == target[j]) like previous questions 31 | */ 32 | int findMinimumOperationsTabul(string &mainStr, string &target) { 33 | int n = mainStr.size(), m = target.size(); 34 | vector> dp(n + 1, vector(m + 1)); 35 | 36 | //base cases 37 | for (int i = 0; i <= n; i++) dp[i][0] = i; 38 | for (int j = 0; j <= m; j++) dp[0][j] = j; 39 | 40 | //we have set the bases for 0 so start from 1 41 | for (int i = 1; i <= n; i++) { 42 | for (int j = 1; j <= m; j++) { 43 | if (mainStr[i - 1] == target[j - 1]) 44 | dp[i][j] = dp[i - 1][j - 1]; 45 | else dp[i][j] = min({1 + dp[i][j - 1], 1 + dp[i - 1][j], 1 + dp[i - 1][j - 1]}); 46 | } 47 | } 48 | return dp[n][m]; 49 | } 50 | 51 | /*space optimised approach */ 52 | int findMinimumOperationsSpaceOpt(string &mainStr, string &target) { 53 | int n = mainStr.size(), m = target.size(); 54 | vectorprev(m + 1), curr(m + 1); 55 | 56 | //base cases 57 | for (int j = 0; j <= m; j++) prev[j] = j; 58 | 59 | //we have set the bases for 0 so start from 1 60 | for (int i = 1; i <= n; i++) { 61 | curr[0] = i;//for every first element in every row the element should be equals to i 62 | for (int j = 1; j <= m; j++) { 63 | if (mainStr[i - 1] == target[j - 1]) 64 | curr[j] = prev[j - 1]; 65 | else curr[j] = min({1 + curr[j - 1], 1 + prev[j], 1 + prev[j - 1]}); 66 | } 67 | prev = curr; 68 | } 69 | return prev[m]; 70 | } 71 | 72 | int editDistance(string & mainStr, string & target) { 73 | int n = mainStr.size(), m = target.size(); 74 | 75 | /*for memoization */ 76 | // vector> dp(n + 1, vector(m + 1, -1)); 77 | // int res = findMinimumOperations(n, m, mainStr, target, dp); 78 | 79 | 80 | /*for tabulation*/ 81 | // int res = findMinimumOperationsTabul(mainStr, target); 82 | 83 | /*for space optimised approach*/ 84 | int res = findMinimumOperationsSpaceOpt(mainStr, target); 85 | return res; 86 | } 87 | 88 | int main() { 89 | 90 | string mainStr, target; 91 | cin >> mainStr >> target; 92 | cout << editDistance(mainStr, target); 93 | return 0; 94 | 95 | } -------------------------------------------------------------------------------- /DP on Strings/Longest Common Subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*Recursive + Memoisation code */ 5 | int lcs(int i, int j , string &str1, string &str2, vector> &dp) { 6 | //base case 7 | if (i < 0 or j < 0) return 0; 8 | if (dp[i][j] != -1) return dp[i][j]; 9 | //if the current both characters are same then 10 | if (str1[i] == str2[j]) 11 | return dp[i][j] = 1 + lcs(i - 1, j - 1, str1, str2, dp); 12 | /* else if both the ith and jth characters are different then there can be 13 | two possibilities one for the str1 and another for str2 to break*/ 14 | return dp[i][j] = max(lcs(i - 1, j, str1, str2, dp), lcs(i, j - 1, str1, str2, dp)); 15 | } 16 | 17 | 18 | 19 | /*Recursive + Memoisation code after shifting the index */ 20 | int lcsAfterShifting(int i, int j , string &str1, string &str2, vector> &dp) { 21 | //base case 22 | if (i == 0 or j == 0) return 0; 23 | if (dp[i][j] != -1) return dp[i][j]; 24 | //if the current both characters are same then 25 | if (str1[i - 1] == str2[j - 1]) 26 | return dp[i][j] = 1 + lcsAfterShifting(i - 1, j - 1, str1, str2, dp); 27 | /* else if both the ith and jth characters are different then there can be 28 | two possibilities one for the str1 and another for str2 to break*/ 29 | return dp[i][j] = max(lcsAfterShifting(i - 1, j, str1, str2, dp), lcsAfterShifting(i, j - 1, str1, str2, dp)); 30 | } 31 | 32 | 33 | /*tabulation approach for the same */ 34 | int lcsTabul(string str1, string str2) { 35 | int n = str1.size(), m = str2.size(); 36 | vector> dp(n + 1, vector (m + 1, -1)); 37 | 38 | //if one state is less than zero then another can have no boundations 39 | for (int i = 0 ; i <= n; i++)dp[i][0] = 0;//for the row 40 | for (int i = 0 ; i <= m; i++)dp[0][i] = 0;//for the column 41 | 42 | /*Rest of all stuff */ 43 | for (int i = 1; i <= n; i++) { 44 | for (int j = 1; j <= m; j++) { 45 | if (str1[i - 1] == str2[j - 1]) dp[i][j] = 1 + dp[i - 1][j - 1]; 46 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 47 | } 48 | } 49 | return dp[n][m]; 50 | 51 | } 52 | 53 | 54 | /*space optimiation approach for the same */ 55 | int lcsSpaceOpt(string str1, string str2) { 56 | int n = str1.size(), m = str2.size(); 57 | vector prev(m + 1), curr (m + 1); 58 | 59 | //if one state is less than zero then another can have no boundations 60 | for (int i = 0 ; i <= m; i++)prev[i] = 0;//for the row 61 | 62 | /*Rest of all stuff */ 63 | for (int i = 1; i <= n; i++) { 64 | for (int j = 1; j <= m; j++) { 65 | if (str1[i - 1] == str2[j - 1]) curr[j] = 1 + prev[j - 1]; 66 | else curr[j] = max(prev[j], curr[j - 1]); 67 | } 68 | prev = curr; 69 | } 70 | return prev[m]; 71 | 72 | } 73 | 74 | int longestCommonSubsequence(string str1, string str2) { 75 | int n = str1.size(), m = str2.size(); 76 | 77 | //for memoisation and recursion - 78 | // vector> dp(n, vector (m, -1)); 79 | // int res = lcs(n - 1, m - 1, str1, str2, dp); 80 | 81 | //for memoisation after shifting 82 | // vector> dp(n + 1, vector (m + 1, -1)); 83 | // int res = lcsAfterShifting(n, m, str1, str2, dp); 84 | 85 | //for tabulation 86 | // int res = lcsTabul(str1, str2); 87 | 88 | //for space optimisation one 89 | int res = lcsSpaceOpt(str1, str2); 90 | 91 | return res; 92 | } 93 | 94 | int main() { 95 | string str1, str2; 96 | cin >> str1 >> str2; 97 | cout << longestCommonSubsequence(str1, str2); 98 | return 0; 99 | 100 | } -------------------------------------------------------------------------------- /DP on Strings/Longest Common Substring.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int longestCommonSubstringTabul(string &str1, string &str2) { 5 | int n = str1.size(), m = str2.size(); 6 | vector> dp(n + 1, vector (m + 1, -1)); 7 | 8 | //if one state is less than zero then another can have no boundations 9 | for (int i = 0 ; i <= n; i++)dp[i][0] = 0;//for the row 10 | for (int i = 0 ; i <= m; i++)dp[0][i] = 0;//for the column 11 | 12 | /*Rest of all stuff */ 13 | int maxLength = INT_MIN; 14 | for (int i = 1; i <= n; i++) { 15 | for (int j = 1; j <= m; j++) { 16 | if (str1[i - 1] == str2[j - 1]) 17 | dp[i][j] = 1 + dp[i - 1][j - 1], maxLength = max(maxLength, dp[i][j]); 18 | else dp[i][j] = 0; 19 | } 20 | } 21 | return maxLength; 22 | 23 | } 24 | 25 | 26 | /*tabulation approach for the same */ 27 | int lcsSpaceOpt(string str1, string str2) { 28 | int n = str1.size(), m = str2.size(); 29 | vector prev(m + 1), curr (m + 1); 30 | 31 | //if one state is less than zero then another can have no boundations 32 | for (int i = 0 ; i <= m; i++)prev[i] = 0;//for the row 33 | int maxLength = INT_MIN; 34 | /*Rest of all stuff */ 35 | for (int i = 1; i <= n; i++) { 36 | for (int j = 1; j <= m; j++) { 37 | if (str1[i - 1] == str2[j - 1]) curr[j] = 1 + prev[j - 1], maxLength = max(maxLength, curr[j]); 38 | else curr[j] = 0; 39 | } 40 | prev = curr; 41 | } 42 | return maxLength; 43 | 44 | } 45 | 46 | int giveLongestCommonSubstring(string str1, string str2) { 47 | int n = str1.size(), m = str2.size(); 48 | 49 | //for tabulation 50 | // int res = longestCommonSubstringTabul(str1, str2); 51 | 52 | //for space optimisation one 53 | int res = lcsSpaceOpt(str1, str2); 54 | 55 | return res; 56 | } 57 | 58 | int main() { 59 | // #if 60 | string str1, str2; 61 | cin >> str1 >> str2; 62 | cout << giveLongestCommonSubstring(str1, str2); 63 | return 0; 64 | 65 | } -------------------------------------------------------------------------------- /DP on Strings/Longest Palindromic Subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //we can also use memoisation or space optimised approach but i used Tabulation here 5 | 6 | /* ------------------------This is to print the length of longest palindromic subsequence------------------------ */ 7 | 8 | int longestPalindromicSubsequence(string &s) { 9 | int n = s.size(); 10 | vector> dp(n + 1, vector (n + 1)); 11 | string rev = s; 12 | reverse(begin(rev), end(rev)); 13 | //base cases 14 | for (int i = 0; i <= n; i++) { 15 | dp[0][i] = 0; 16 | dp[i][0] = 0; 17 | } 18 | //rest of the cases 19 | for (int i = 1; i <= n; i++) { 20 | for (int j = 1; j <= n; j++) { 21 | //if both the characters are same then 22 | if (s[i - 1] == rev[j - 1]) { 23 | dp[i][j] = 1 + dp[i - 1][j - 1]; 24 | } 25 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 26 | } 27 | } 28 | return dp[n][n]; 29 | } 30 | 31 | 32 | 33 | /*----------------------------This is to print one of the longest Palindromic subsequence----------------------------*/ 34 | 35 | string printLongestPalindromicSubsequence(string &s) { 36 | int n = s.size(); 37 | vector> dp(n + 1, vector (n + 1)); 38 | string rev = s; 39 | reverse(begin(rev), end(rev)); 40 | //base cases 41 | for (int i = 0; i <= n; i++) { 42 | dp[0][i] = 0; 43 | dp[i][0] = 0; 44 | } 45 | //rest of the cases 46 | for (int i = 1; i <= n; i++) { 47 | for (int j = 1; j <= n; j++) { 48 | //if both the characters are same then 49 | if (s[i - 1] == rev[j - 1]) { 50 | dp[i][j] = 1 + dp[i - 1][j - 1]; 51 | } 52 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 53 | } 54 | } 55 | int row = n, col = n; 56 | string res; 57 | while (row > 0 and col > 0) { 58 | /*same as the recurrence we have two choices either the character is same or not 59 | if not then take the max and move accordingly */ 60 | 61 | if (s[row - 1] == rev[col - 1]) { 62 | res = s[row - 1] + res; 63 | row--, col--; 64 | } 65 | else if (dp[row - 1][col] > dp[row][col - 1]) row--; 66 | else col--; 67 | } 68 | return res; 69 | } 70 | 71 | int main() { 72 | string s; cin >> s; 73 | cout << longestPalindromicSubsequence(s) << " "; 74 | cout << printLongestPalindromicSubsequence(s) ; 75 | return 0; 76 | 77 | } -------------------------------------------------------------------------------- /DP on Strings/Minimum Insertions To convert a string into Palindromic String.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* recrusion + memoization code - We can also use Tabulation and Space optimised code for 5 | More see it in the Anothe code i.e., LCS or LPS */ 6 | 7 | int findLPSMemo(int i, int j, string &mainStr, string &rev, vector> &dp) { 8 | //base case 9 | if (i == 0 or j == 0) return 0; 10 | if (dp[i][j] != -1) return dp[i][j]; 11 | if (mainStr[i - 1] == rev[j - 1]) 12 | return dp[i][j] = 1 + findLPSMemo(i - 1, j - 1, mainStr, rev, dp); 13 | return dp[i][j] = max(findLPSMemo(i - 1, j, mainStr, rev, dp), 14 | findLPSMemo(i, j - 1, mainStr, rev, dp)); 15 | } 16 | 17 | 18 | int minimumInserionsToMakePalindromicString(string &str) { 19 | int n = str.size(); 20 | string rev = str; 21 | //for memoization 22 | reverse(rev.begin(), rev.end()); 23 | 24 | vector> dp(n + 1, vector(n + 1, -1)); 25 | int lengthOfLPS = findLPSMemo(n, n, str, rev, dp); 26 | 27 | int minimumCharacersNeedToInsert = n - lengthOfLPS; 28 | 29 | return minimumCharacersNeedToInsert; 30 | } 31 | 32 | int main() { 33 | string s; 34 | cin >> s; 35 | cout << minimumInserionsToMakePalindromicString(s); 36 | return 0; 37 | 38 | } 39 | //@singhkunal01 -------------------------------------------------------------------------------- /DP on Strings/Minimum Number of Insertion-Deletions to Make both strings Equal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | /*----------------tabulation approach , we can also use Memoization and Space optimization ----------------*/ 6 | 7 | int findLCSOfBothStrings(string &str1, string &str2) { 8 | int n = str1.size(), m = str2.size(); 9 | vector> dp(n + 1, vector (m + 1, -1)); 10 | for (int i = 0 ; i <= n; i++)dp[i][0] = 0;//for the row 11 | for (int i = 0 ; i <= m; i++)dp[0][i] = 0;//for the column 12 | for (int i = 1; i <= n; i++) { 13 | for (int j = 1; j <= m; j++) { 14 | if (str1[i - 1] == str2[j - 1]) dp[i][j] = 1 + dp[i - 1][j - 1]; 15 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 16 | } 17 | } 18 | return dp[n][m]; 19 | } 20 | 21 | int minimumInserionsDeletionsToMakeBothStringsEqual(string &s1, string &s2) { 22 | int n = s1.size(), m = s2.size(); 23 | int lcsOfBoth = findLCSOfBothStrings(s1, s2); 24 | int minOperationsRequired = (n + m) - (2 * lcsOfBoth); 25 | return minOperationsRequired; 26 | } 27 | 28 | int main() { 29 | string s1, s2; 30 | cin >> s1 >> s2; 31 | cout << minimumInserionsDeletionsToMakeBothStringsEqual(s1, s2); 32 | return 0; 33 | 34 | } -------------------------------------------------------------------------------- /DP on Strings/Print Longest Common Subsequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*tabulation approach */ 5 | string printLCS(string str1, string str2) { 6 | int n = str1.size(), m = str2.size(); 7 | vector> dp(n + 1, vector (m + 1, -1)); 8 | 9 | //if one state is less than zero then another can have no boundations 10 | for (int i = 0 ; i <= n; i++)dp[i][0] = 0;//for the row 11 | for (int i = 0 ; i <= m; i++)dp[0][i] = 0;//for the column 12 | 13 | /*Rest of all stuff */ 14 | for (int i = 1; i <= n; i++) { 15 | for (int j = 1; j <= m; j++) { 16 | if (str1[i - 1] == str2[j - 1]) dp[i][j] = 1 + dp[i - 1][j - 1]; 17 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 18 | } 19 | } 20 | // till here we have the designed table for our answer with the help of that we are going to find the string 21 | // for (int i = 0; i <= n; i++) {for (int j = 0; j <= m; j++) cout << dp[i][j] << " "; cout << endl; } return ""; 22 | 23 | /*For the example - str1 = abcde , str2 = bdgek 24 | 25 | Table will look like - 26 | 0 0 0 0 0 0 27 | 0 0 0 0 0 0 28 | 0 1 1 1 1 1 29 | 0 1 1 1 1 1 30 | 0 1 2 2 2 2 31 | 0 1 2 2 3 [3] this is our answer by the help of this we find the required LCS 32 | 33 | For more explanation Go to Lecture of Striver bhaiya's LCS video 34 | */ 35 | int row = n, col = m; 36 | string res; 37 | while (row > 0 and col > 0) { 38 | /*same as the recurrence we have two choices either the character is same or not 39 | if not then take the max and move accordingly */ 40 | 41 | if (str1[row - 1] == str2[col - 1]) { 42 | res = str1[row - 1] + res; 43 | row--, col--; 44 | } 45 | else if (dp[row - 1][col] > dp[row][col - 1]) row--; 46 | else col--; 47 | } 48 | return res; 49 | } 50 | 51 | int main() { 52 | string s, t; cin >> s >> t; 53 | cout << printLCS(s, t); 54 | return 0; 55 | 56 | } -------------------------------------------------------------------------------- /DP on Strings/Shortest Common Supersequence.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*Tabulation approach to find the longest common subsequence because with the help of this 5 | we can easily find the exact supersequence too - */ 6 | 7 | 8 | /*-------------------This is to the get the length of that supersequence-------------------*/ 9 | 10 | int findLCSTabul(string &str1, string &str2) { 11 | int n = str1.size(), m = str2.size(); 12 | vector> dp(n + 1, vector (m + 1, -1)); 13 | 14 | for (int i = 0 ; i <= n; i++)dp[i][0] = 0;//for the row 15 | for (int i = 0 ; i <= m; i++)dp[0][i] = 0;//for the column 16 | 17 | for (int i = 1; i <= n; i++) { 18 | for (int j = 1; j <= m; j++) { 19 | if (str1[i - 1] == str2[j - 1]) dp[i][j] = 1 + dp[i - 1][j - 1]; 20 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 21 | } 22 | } 23 | /* for (auto i : dp) { 24 | for (auto j : i) 25 | cout << j << " "; 26 | cout << endl; 27 | } 28 | */ 29 | return dp[n][m]; 30 | } 31 | 32 | 33 | /*-------------------This is to print that supersequence------------------- */ 34 | string printShortestCommonSupersequence(string &str1, string &str2) { 35 | int n = str1.size(), m = str2.size(); 36 | vector> dp(n + 1, vector (m + 1, -1)); 37 | 38 | for (int i = 0 ; i <= n; i++)dp[i][0] = 0;//for the row 39 | for (int i = 0 ; i <= m; i++)dp[0][i] = 0;//for the column 40 | 41 | for (int i = 1; i <= n; i++) { 42 | for (int j = 1; j <= m; j++) { 43 | if (str1[i - 1] == str2[j - 1]) dp[i][j] = 1 + dp[i - 1][j - 1]; 44 | else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 45 | } 46 | } 47 | int row = n, col = m; 48 | string res; 49 | while (row > 0 and col > 0) { 50 | /*same as the recurrence we have two choices either the character is same or not 51 | if not then take the max and move accordingly */ 52 | if (str1[row - 1] == str2[col - 1]) { 53 | res = str1[row - 1] + res; 54 | row--, col--; 55 | } 56 | else if (dp[row - 1][col] > dp[row][col - 1]) { 57 | res = str1[row - 1] + res; 58 | row--; 59 | } 60 | else { 61 | res = str2[col - 1] + res; 62 | col--; 63 | } 64 | } 65 | //now if there is something remaining from str1 or str2 then for that we have to handle the cases 66 | while (row) res = str1[row - 1] + res, row--; 67 | while (col) res = str2[col - 1] + res, col--; 68 | return res; 69 | } 70 | 71 | int shortestCommonSupersequence(string &str1, string &str2) { 72 | int n = str1.size(), m = str2.size(); 73 | int lengthOfLCS = findLCSTabul(str1, str2); 74 | //total length of required supersequence is n + m - lengthOfLCS 75 | int lengthOfSCS = n + m - lengthOfLCS; 76 | return lengthOfSCS; 77 | } 78 | 79 | 80 | int main() { 81 | 82 | string str1, str2; cin >> str1 >> str2; 83 | cout << shortestCommonSupersequence(str1, str2) << endl; 84 | cout << printShortestCommonSupersequence(str1, str2) << endl; 85 | return 0; 86 | 87 | } -------------------------------------------------------------------------------- /DP on Strings/Wildcard Matching.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | bool wildcardMatch(int i, int j, string &pattern, string &text, vector>&dp) { 5 | 6 | //base cases 7 | //1 . if both the strings exhausted 8 | if (i < 0 and j < 0) return true; 9 | // 2. If string first got exhausted and string 2 has some characters to be match 10 | if (i<0 and j >= 0) return false; 11 | /* 3.if string 2 got exhausted and some chars are remaining in the first string then there is observation 12 | like according to codestudio problem first string has ? and * but according to leetcode 2 string has ? and * 13 | so whatever string has ? and * if string other than that is empty then there have to only * 14 | in the another string because only * will match empty characters so*/ 15 | if (j<0 and i >= 0) { 16 | for (int k = 0; k <= i; k++ )if (pattern[k] != '*') 17 | return false; 18 | return true; 19 | } 20 | if (dp[i][j] != -1) return dp[i][j]; 21 | //now main logic 22 | // if both the char matched or a single character is matched with ? then move both pointers 23 | if (pattern[i] == text[j] or pattern[i] == '?') return dp[i][j] = wildcardMatch(i - 1, j - 1, pattern, text, dp); 24 | if (pattern[i] == '*') return dp[i][j] = (wildcardMatch(i - 1, j, pattern, text, dp) | wildcardMatch(i, j - 1, pattern, text, dp)); 25 | return dp[i][j] = false; 26 | 27 | } 28 | 29 | 30 | /*shifting memoization code */ 31 | bool wildcardMatchShifting(int i, int j, string &pattern, string &text, vector>&dp) { 32 | 33 | //base cases 34 | //1 . if both the strings exhausted 35 | if (i == 0 and j == 0) return true; 36 | // 2. If string first got exhausted and string 2 has some characters to be match 37 | if (i == 0 and j > 0) return false; 38 | /* 3.if string 2 got exhausted and some chars are remaining in the first string then there is observation 39 | like according to codestudio problem first string has ? and * but according to leetcode 2 string has ? and * 40 | so whatever string has ? and * if string other than that is empty then there have to only * 41 | in the another string because only * will match empty characters so*/ 42 | if (j == 0 and i > 0) { 43 | for (int k = 1; k <= i; k++ )if (pattern[k - 1] != '*') 44 | return false; 45 | return true; 46 | } 47 | if (dp[i][j] != -1) return dp[i][j]; 48 | //now main logic 49 | // if both the char matched or a single character is matched with ? then move both pointers 50 | if (pattern[i - 1] == text[j - 1] or pattern[i - 1] == '?') return dp[i][j] = wildcardMatchShifting(i - 1, j - 1, pattern, text, dp); 51 | if (pattern[i - 1] == '*') return dp[i][j] = (wildcardMatchShifting(i - 1, j, pattern, text, dp) | wildcardMatchShifting(i, j - 1, pattern, text, dp)); 52 | return dp[i][j] = false; 53 | 54 | } 55 | 56 | /*tabulation code - */ 57 | bool wildcardMatchTabul(string &pattern, string&text) { 58 | int n = pattern.size(), m = text.size(); 59 | vector> dp(n + 1, vector(m + 1, false)); 60 | //base cases comparing with memoisation code 61 | //1. base case 62 | dp[0][0] = true; 63 | //2.base case 64 | for (int j = 1; j <= m; j++) dp[0][j] = false; 65 | //3. base case 66 | for (int i = 1; i <= n; i++) { 67 | bool flag = true; 68 | for (int k = 1; k <= i; k++) { 69 | if (pattern[k - 1] != '*') {flag = false; break;}; 70 | } 71 | dp[i][0] = flag; 72 | } 73 | //main logic 74 | 75 | for (int i = 1; i <= n; i++) { 76 | for (int j = 1; j <= m; j++) { 77 | if (pattern[i - 1] == text[j - 1] or pattern[i - 1] == '?') 78 | dp[i][j] = dp[i - 1][j - 1]; 79 | else if (pattern[i - 1] == '*') 80 | dp[i][j] = dp[i - 1][j] | dp[i][j - 1]; 81 | else dp[i][j] = false; 82 | } 83 | } 84 | return dp[n][m]; 85 | } 86 | 87 | //space optimisation approach 88 | /*tabulation code - */ 89 | bool wildcardMatchSpaceOpt(string &pattern, string&text) { 90 | int n = pattern.size(), m = text.size(); 91 | vector prev(m + 1), curr(m + 1); 92 | //base cases comparing with memoisation code 93 | //1. base case 94 | prev[0] = curr[0] = true; 95 | //2.base case 96 | for (int j = 1; j <= m; j++) prev[j] = false; 97 | //3. base case , is in the first loop 98 | //main logic 99 | 100 | for (int i = 1; i <= n; i++) { 101 | 102 | //everytime columns first element assigned to be false 103 | bool flag = true; 104 | for (int k = 1; k <= i; k++) { 105 | if (pattern[k - 1] != '*') {flag = false; break;}; 106 | } 107 | curr[0] = flag; 108 | 109 | for (int j = 1; j <= m; j++) { 110 | if (pattern[i - 1] == text[j - 1] or pattern[i - 1] == '?') 111 | curr[j] = prev[j - 1]; 112 | else if (pattern[i - 1] == '*') 113 | curr[j] = prev[j] | curr[j - 1]; 114 | else curr[j] = false; 115 | } 116 | prev = curr; 117 | } 118 | return prev[m]; 119 | } 120 | 121 | 122 | bool isMatch(string &pattern, string &text) { 123 | int n = pattern.size(), m = text.size(); 124 | 125 | //for memoization 126 | // vector> dp(n, vector(m, -1)); 127 | // bool res = wildcardMatch(n - 1, m - 1, pattern, text, dp); 128 | //for shifting of indices 129 | vector> dp(n + 1, vector(m + 1, -1)); 130 | // bool res = wildcardMatchShifting(n, m, pattern, text, dp); 131 | 132 | //for tabulation 133 | // bool res = wildcardMatchTabul(pattern, text); 134 | //for space optimistion 135 | bool res = wildcardMatchSpaceOpt(pattern, text); 136 | return res; 137 | } 138 | 139 | int main() { 140 | string pattern, text; 141 | cin >> pattern >> text; 142 | cout << isMatch(pattern, text); 143 | return 0; 144 | 145 | } -------------------------------------------------------------------------------- /DP on Subsequences/0-1 Knapsack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* Recursive + Memoisation code 5 | 6 | Recursive- TC - O(2^N) , SC -O(N) 7 | Memoisation - TC - O(N*maxWeight) , SC - O(N*maxWeight)+O(N) 8 | */ 9 | int giveMaxWeightMemo(int currHouse, vector &weight, vector &value, int maxWeight, vector>&dp) { 10 | if (currHouse == 0) return (weight[0] <= maxWeight) ? value[0] : 0; 11 | if (dp[currHouse][maxWeight] != -1) return dp[currHouse][maxWeight]; 12 | int notPick = giveMaxWeightMemo(currHouse - 1, weight, value, maxWeight, dp); 13 | int pick = INT_MIN; 14 | if (weight[currHouse] <= maxWeight) 15 | pick = value[currHouse] + giveMaxWeightMemo(currHouse - 1, weight, value, maxWeight - weight[currHouse], dp); 16 | return dp[currHouse][maxWeight] = max(pick, notPick); 17 | } 18 | 19 | /*Tabulation approach*/ 20 | int giveMaxWeightTabu(vector &weight, vector &value, int n, int &maxWeight) { 21 | // Write your code here 22 | vector> dp(n, vector(maxWeight + 1)); 23 | for (int currHouse = weight[0]; currHouse <= maxWeight; currHouse++)dp[0][currHouse] = value[0]; 24 | for (int currHouse = 1; currHouse < n; currHouse++) { 25 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++) { 26 | int notPick = dp[currHouse - 1][fromWeight]; 27 | int pick = INT_MIN; 28 | if (weight[currHouse] <= fromWeight) 29 | pick = value[currHouse] + dp[currHouse - 1][fromWeight - weight[currHouse]]; 30 | dp[currHouse][fromWeight] = max(pick, notPick); 31 | } 32 | } 33 | return dp[n - 1][maxWeight]; 34 | } 35 | 36 | 37 | int giveMaxWeightSpaceOpt(vector &weight, vector &value, int n, int &maxWeight) { 38 | // Write your code here 39 | vector prev(maxWeight + 1), curr(maxWeight + 1); 40 | for (int currHouse = weight[0]; currHouse <= maxWeight; currHouse++)prev[currHouse] = value[0]; 41 | for (int currHouse = 1; currHouse < n; currHouse++) { 42 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++) { 43 | int notPick = prev[fromWeight]; 44 | int pick = INT_MIN; 45 | if (weight[currHouse] <= fromWeight) 46 | pick = value[currHouse] + prev[fromWeight - weight[currHouse]]; 47 | curr[fromWeight] = max(pick, notPick); 48 | } 49 | prev = curr; 50 | } 51 | return prev[maxWeight]; 52 | } 53 | 54 | /*...................Most optimal approach using single array optimisation...................*/ 55 | int mostOptimalResultant(vector &weight, vector &value, int n, int &maxWeight) { 56 | // Write your code here 57 | vector prev(maxWeight + 1); 58 | for (int currHouse = weight[0]; currHouse <= maxWeight; currHouse++)prev[currHouse] = value[0]; 59 | for (int currHouse = 1; currHouse < n; currHouse++) { 60 | for (int fromWeight = maxWeight; fromWeight >= 0; fromWeight--) { 61 | int notPick = prev[fromWeight]; 62 | int pick = INT_MIN; 63 | if (weight[currHouse] <= fromWeight) 64 | pick = value[currHouse] + prev[fromWeight - weight[currHouse]]; 65 | prev[fromWeight] = max(pick, notPick); 66 | } 67 | } 68 | return prev[maxWeight]; 69 | } 70 | 71 | 72 | 73 | //main knapsack function 74 | int knapsack(vector &weight, vector &value, int n, int &maxWeight) { 75 | // Write your code here 76 | // vector> dp(n, vector(maxWeight + 1, -1)); 77 | //memoisation 78 | // int maxCost = giveMaxWeightMemo(n - 1, weight, value, maxWeight, dp); 79 | //tabulation 80 | // int maxCost = giveMaxWeightTabu(weight, value, n, maxWeight); 81 | //space optimisation 82 | // int maxCost = giveMaxWeightSpaceOpt(weight, value, n, maxWeight); 83 | //most optimal result 84 | int maxCost = mostOptimalResultant(weight, value, n, maxWeight); 85 | return maxCost; 86 | } 87 | 88 | 89 | 90 | int main() { 91 | int n; cin >> n; 92 | vectorweight(n), value(n); 93 | for (int &i : weight)cin >> i; 94 | for (int &i : value)cin >> i; 95 | int maxWeight; cin >> maxWeight; 96 | cout << "Max Value : " << knapsack(weight, value, n, maxWeight) << endl; 97 | return 0; 98 | 99 | } -------------------------------------------------------------------------------- /DP on Subsequences/Coin change 2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int findWays(int ind, int amount, vector &coins, vector> &dp) { 5 | //if we are on the 0th index then if the amount is the multiple of the current denomination then only we can pick it 6 | if (ind == 0) { 7 | if (amount % coins[ind] == 0) return 1; 8 | else return 0; 9 | } 10 | /*instead of the upper base case we can also use these two bases cases : 11 | 12 | if(amount == 0) return 0; 13 | if(ind < 0 || amount < 0) return 1e9; 14 | 15 | */ 16 | if (dp[ind][amount] != -1)return dp[ind][amount]; 17 | 18 | int notTake = findWays(ind - 1, amount, coins, dp); 19 | int take = 0; 20 | if (coins[ind] <= amount) take = findWays(ind, amount - coins[ind], coins, dp); 21 | return dp[ind][amount] = (take + notTake); 22 | } 23 | 24 | int findWaysTabul(vector &coins, int amount) { 25 | int n = coins.size(); 26 | vector> dp(n, vector(amount + 1, 0)); 27 | for (int ind = 0; ind <= amount; ind++)if (ind % coins[0] == 0) dp[0][ind] = 1; 28 | for (int ind = 1; ind < n; ind++) { 29 | for (int tempAmount = 0; tempAmount <= amount; tempAmount++) { 30 | int notTake = dp[ind - 1][tempAmount]; 31 | int take = 0; 32 | if (coins[ind] <= tempAmount) take = dp[ind][tempAmount - coins[ind]]; 33 | dp[ind][tempAmount] = (take + notTake); 34 | } 35 | } 36 | int ans = dp[n - 1][amount]; 37 | return ans < 1e8 ? ans : -1; 38 | } 39 | 40 | 41 | // space optimisation approach using 1d Dp 42 | int findWaysSpaceOpt(vector &coins, int amount) { 43 | int n = coins.size(); 44 | vector prev(amount + 1, 0), curr(amount + 1, 0); 45 | for (int ind = 0; ind <= amount; ind++)if (ind % coins[0] == 0) prev[ind] = 1; 46 | for (int ind = 1; ind < n; ind++) { 47 | for (int tempAmount = 0; tempAmount <= amount; tempAmount++) { 48 | int notTake = prev[tempAmount]; 49 | int take = 0; 50 | if (coins[ind] <= tempAmount) take = curr[tempAmount - coins[ind]]; 51 | curr[tempAmount] = (take + notTake); 52 | } 53 | prev = curr; 54 | } 55 | int ans = prev[amount]; 56 | return ans < 1e9 ? ans : -1; 57 | } 58 | 59 | 60 | int coinChange(vector &coins, int amount) 61 | { 62 | // write your code here 63 | int n = coins.size(); 64 | // vector> dp(n, vector(amount + 1, -1)); 65 | //for memoisation + recursion 66 | // int ans = findWays(n - 1, amount, coins, dp); 67 | //for tabulation 68 | // int ans = findWaysTabul(coins, amount); 69 | //space optimised 70 | int ans = findWaysSpaceOpt(coins, amount); 71 | return ans < 1e9 ? ans : -1; 72 | } 73 | 74 | int main() { 75 | int n; 76 | cin >> n; 77 | int amount; cin >> amount; 78 | vector coins(n); 79 | for (int &i : coins)cin >> i; 80 | cout << coinChange(coins, amount); 81 | return 0; 82 | 83 | } -------------------------------------------------------------------------------- /DP on Subsequences/Count Partitions With Given Difference.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //most optimal approach we can also use memoisation or tabulation here 5 | 6 | const int mod = 1e9 + 7; 7 | 8 | // space optimisation approach 9 | int countPossibleSubsetsSpaceOpt(vector &num, int target) { 10 | int n = num.size(); 11 | vector prev(target + 1), curr(target + 1); 12 | 13 | //base cases 14 | /*breaking down the first base case like this , suppose if the index is 0 and target is 0 which means we have to fill 15 | dp[0][0] by 2 but under the condition if (num[0] == 0) for the other rest cases */ 16 | 17 | prev[0] = (num[0] == 0) ? 2 : 1; 18 | 19 | /* now for the seond base where the index is 0 but target can be equal to the num[ind] i.e., num[0] , but for that we have to take care of some 20 | conditions like if (num[0] != 0) because previously we have take care of when the num[0] == 0 and as similar to the SUBSET SUM EQUAL TO TARGET 21 | we have to add the other condition for the first index which we pick only when num[0] <= target;*/ 22 | if (num[0] != 0 and num[0] <= target) prev[num[0]] = 1; 23 | 24 | //for the rest stuff 25 | for (int ind = 1; ind < n; ind++) { 26 | for (int tar = 0; tar <= target; tar++) { 27 | int notPick = prev[tar] % mod; 28 | int pick = 0; 29 | if (num[ind] <= tar) pick = prev[tar - num[ind]] % mod; 30 | curr[tar] = (pick % mod + notPick % mod) % mod; 31 | } 32 | prev = curr; 33 | } 34 | return prev[target] % mod; 35 | } 36 | 37 | 38 | int countPartitions(int n, int d, vector &arr) { 39 | // Write your code here. 40 | int target = 0; 41 | for (int i : arr) target += i; 42 | if (target - d < 0 or ((target - d) & 1)) return 0; 43 | /* 44 | lets say total sum will be Target now we know that for two subsets say s1,s2 - 45 | target = s1+s2 or s1 =target - s2, -------------- (1) 46 | on the therr hand in the question given that the difference of two required subsets will be D so, 47 | D= s1 - s2------------------(2) 48 | from eqn (1), 49 | D = target - s2 -s2 = target - 2s2 50 | hence s2 = (target - D)/2 so this will be our target and from the last problem we can observe that if we find find one subset 51 | then automatically 2nd is in our hand 52 | */ 53 | return countPossibleSubsetsSpaceOpt(arr, (target - d) / 2); 54 | } 55 | 56 | int main() { 57 | 58 | int n; cin >> n; 59 | int diff; cin >> diff; 60 | vector arr(n); 61 | for (int &i : arr) cin >> i; 62 | cout << "Count : " << countPartitions(n, diff, arr) << endl; 63 | return 0; 64 | 65 | } -------------------------------------------------------------------------------- /DP on Subsequences/Count Subset with sum K.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //code using recursive approach TC -O(2^N) SC - O(N)auxiliary stack space 5 | int countPossibleSubsets(int ind, vector &nums, int target) { 6 | //base case 7 | if (target == 0)return 1; 8 | if (ind == 0) return nums[ind] == target; 9 | //as the question is on subsets then we can break down in terms of indices 10 | int pick = 0; 11 | if (nums[ind] <= target)pick = countPossibleSubsets(ind - 1, nums, target - nums[ind]); 12 | int notPick = countPossibleSubsets(ind - 1, nums, target); 13 | return pick + notPick; 14 | } 15 | 16 | 17 | //code for dp memoisation approach 18 | int countPossibleSubsetsMemo(int ind, vector &nums, int target, vector> &memo) { 19 | //base case 20 | if (ind == 0) { 21 | if (target == 0 and nums[ind] == 0) return 2;//if both the condition satisfies then the answer will be 2 if the first index is 0 we have to include it too in our subset 22 | if (target == 0 or nums[ind] == target) return 1; 23 | return 0; 24 | } 25 | 26 | if (memo[ind][target] != -1) return memo[ind][target]; 27 | //as the question is on subsets then we can break down in terms of indices 28 | int pick = 0; 29 | if (nums[ind] <= target)pick = countPossibleSubsetsMemo(ind - 1, nums, target - nums[ind], memo); 30 | int notPick = countPossibleSubsetsMemo(ind - 1, nums, target, memo); 31 | return memo[ind][target] = pick + notPick; 32 | } 33 | 34 | //tabulation approach 35 | int countPossibleSubsetsTabul(vector &num, int target) { 36 | int n = num.size(); 37 | vector> dp(n, vector (target + 1)); 38 | 39 | //base cases 40 | /*breaking down the first base case like this , suppose if the index is 0 and target is 0 which means we have to fill 41 | dp[0][0] by 2 but under the condition if (num[0] == 0) for the other rest cases */ 42 | 43 | dp[0][0] = (num[0] == 0) ? 2 : 1; 44 | 45 | /* now for the seond base where the index is 0 but target can be equal to the num[ind] i.e., num[0] , but for that we have to take care of some 46 | conditions like if (num[0] != 0) because previously we have take care of when the num[0] == 0 and as similar to the SUBSET SUM EQUAL TO TARGET 47 | we have to add the other condition for the first index which we pick only when num[0] <= target;*/ 48 | if (num[0] != 0 and num[0] <= target) dp[0][num[0]] = 1; 49 | 50 | //for the rest stuff 51 | for (int ind = 1; ind < n; ind++) { 52 | for (int tar = 0; tar <= target; tar++) { 53 | int notPick = dp[ind - 1][tar]; 54 | int pick = 0; 55 | if (num[ind] <= tar) pick = dp[ind - 1][tar - num[ind]]; 56 | dp[ind][tar] = pick + notPick; 57 | } 58 | } 59 | return dp[n - 1][target]; 60 | } 61 | 62 | // space optimisation approach 63 | int countPossibleSubsetsSpaceOpt(vector &num, int target) { 64 | int n = num.size(); 65 | vector prev(target + 1), curr(target + 1); 66 | 67 | //base cases 68 | /*breaking down the first base case like this , suppose if the index is 0 and target is 0 which means we have to fill 69 | dp[0][0] by 2 but under the condition if (num[0] == 0) for the other rest cases */ 70 | 71 | prev[0] = (num[0] == 0) ? 2 : 1; 72 | 73 | /* now for the seond base where the index is 0 but target can be equal to the num[ind] i.e., num[0] , but for that we have to take care of some 74 | conditions like if (num[0] != 0) because previously we have take care of when the num[0] == 0 and as similar to the SUBSET SUM EQUAL TO TARGET 75 | we have to add the other condition for the first index which we pick only when num[0] <= target;*/ 76 | if (num[0] != 0 and num[0] <= target) prev[num[0]] = 1; 77 | 78 | //for the rest stuff 79 | for (int ind = 1; ind < n; ind++) { 80 | for (int tar = 0; tar <= target; tar++) { 81 | int notPick = prev[tar]; 82 | int pick = 0; 83 | if (num[ind] <= tar) pick = prev[tar - num[ind]]; 84 | curr[tar] = pick + notPick; 85 | } 86 | prev = curr; 87 | } 88 | return prev[target]; 89 | } 90 | 91 | 92 | int findWays(vector &num, int tar) { 93 | // Write your code here. 94 | int n = num.size(); 95 | vector> memo(n , vector(tar + 1, -1)); 96 | // int result = countPossibleSubsets(n - 1, num, tar); 97 | // int result = countPossibleSubsetsMemo(n - 1, num, tar, memo); 98 | // int result = countPossibleSubsetsTabul(num, tar); 99 | int result = countPossibleSubsetsSpaceOpt(num, tar); 100 | return result; 101 | } 102 | 103 | int main() { 104 | 105 | int n; cin >> n; 106 | int target; cin >> target; 107 | vector arr(n); 108 | for (int &i : arr) cin >> i; 109 | cout << "Total Ways : " << findWays(arr, target) << endl; 110 | return 0; 111 | 112 | } 113 | -------------------------------------------------------------------------------- /DP on Subsequences/Minimum Coins.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int findWays(int ind, int amount, vector &coins, vector> &dp) { 5 | //if we are on the 0th index then if the amount is the multiple of the current denomination then only we can pick it 6 | if (ind == 0) { 7 | if (amount % coins[ind] == 0) return amount / coins[0]; 8 | else return 1e9; 9 | } 10 | /*instead of the upper base case we can also use these two bases cases : 11 | 12 | if(amount == 0) return 0; 13 | if(ind < 0 || amount < 0) return 1e9; 14 | 15 | */ 16 | if (dp[ind][amount] != -1)return dp[ind][amount]; 17 | 18 | int notTake = findWays(ind - 1, amount, coins, dp); 19 | int take = 1e9; 20 | if (coins[ind] <= amount) take = 1 + findWays(ind, amount - coins[ind], coins, dp); 21 | return dp[ind][amount] = min(take, notTake); 22 | } 23 | 24 | int findWaysTabul(vector &coins, int amount) { 25 | int n = coins.size(); 26 | vector> dp(n, vector(amount + 1, 1e8)); 27 | for (int ind = 0; ind <= amount; ind++)if (ind % coins[0] == 0) dp[0][ind] = ind / coins[0]; 28 | for (int ind = 1; ind < n; ind++) { 29 | for (int tempAmount = 0; tempAmount <= amount; tempAmount++) { 30 | int notTake = dp[ind - 1][tempAmount]; 31 | int take = 1e8; 32 | if (coins[ind] <= tempAmount) take = 1 + dp[ind][tempAmount - coins[ind]]; 33 | dp[ind][tempAmount] = min(take, notTake); 34 | } 35 | } 36 | int ans = dp[n - 1][amount]; 37 | return ans < 1e8 ? ans : -1; 38 | } 39 | 40 | 41 | // space optimisation approach using 1d Dp 42 | int findWaysSpaceOpt(vector &coins, int amount) { 43 | int n = coins.size(); 44 | vector prev(amount + 1, 1e9), curr(amount + 1, 1e9); 45 | for (int ind = 0; ind <= amount; ind++)if (ind % coins[0] == 0) prev[ind] = ind / coins[0]; 46 | for (int ind = 1; ind < n; ind++) { 47 | for (int tempAmount = 0; tempAmount <= amount; tempAmount++) { 48 | int notTake = prev[tempAmount]; 49 | int take = 1e9; 50 | if (coins[ind] <= tempAmount) take = 1 + curr[tempAmount - coins[ind]]; 51 | curr[tempAmount] = min(take, notTake); 52 | } 53 | prev = curr; 54 | } 55 | int ans = prev[amount]; 56 | return ans < 1e9 ? ans : -1; 57 | } 58 | 59 | 60 | int minimumElements(vector &coins, int amount) 61 | { 62 | // write your code here 63 | int n = coins.size(); 64 | // vector> dp(n, vector(amount + 1, -1)); 65 | //for memoisation + recursion 66 | // int ans = findWays(n - 1, amount, coins, dp); 67 | //for tabulation 68 | int ans = findWaysTabul(coins, amount); 69 | //space optimised 70 | // int ans = findWaysSpaceOpt(coins, amount); 71 | return ans < 1e9 ? ans : -1; 72 | } 73 | 74 | int main() { 75 | int n; 76 | cin >> n; 77 | int amount; cin >> amount; 78 | vector coins(n); 79 | for (int &i : coins)cin >> i; 80 | cout << minimumElements(coins, amount); 81 | return 0; 82 | 83 | } -------------------------------------------------------------------------------- /DP on Subsequences/Partition Equal subset sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*We can also use Recursive , Memoisation ,Tabulation and Space optimised in it but for better complexity we use 5 | most optimal which required only sum/2 space */ 6 | 7 | bool partitionChecker(int target, vector &arr, int n) { 8 | vector prev(target + 1, false), curr(target + 1, false); 9 | prev[0] = curr[0] = true; 10 | prev[arr[0]] = true; 11 | for (int index = 1; index < n; index++) { 12 | for (int givenTarget = 1; givenTarget <= target ; givenTarget++) { 13 | bool notPick = prev[givenTarget]; 14 | bool pick = false; 15 | if (givenTarget >= arr[index]) pick = prev[givenTarget - arr[index]]; 16 | curr[givenTarget] = (pick or notPick); 17 | } 18 | prev = curr; 19 | } 20 | return prev[target]; 21 | } 22 | 23 | 24 | bool canPartition(vector &arr, int n) 25 | { 26 | // Write your code here. 27 | int totalSum = accumulate(arr.begin(), arr.end(), 0); 28 | if (totalSum & 1) return false; 29 | return partitionChecker(totalSum / 2, arr, n); 30 | } 31 | 32 | int main() { 33 | int n; cin >> n; 34 | vector arr(n); 35 | for (int &i : arr) cin >> i; 36 | if (canPartition(arr, n)) cout << "Can Be partitioned" << endl; 37 | else cout << "Can not Be partitioned" << endl; 38 | return 0; 39 | 40 | } -------------------------------------------------------------------------------- /DP on Subsequences/Partition a set into two subsets such that the difference of subset sums is minimum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /*This code is valid only for the Codestudio one problem not 5 | for the leetcode one because leetcode one has negatives also*/ 6 | 7 | //most optimal approach 8 | int minSubsetSumDifference(vector& arr, int n) 9 | { 10 | int target = accumulate(arr.begin(), arr.end(), 0); 11 | vector> dp(n, vector (target + 1, false)); 12 | //for the first base case considering target as 0 13 | for (int i = 0 ; i < n; i++) dp[i][0] = true; 14 | //for the second base considering the index as 0 15 | if (arr[0] <= target)dp[0][arr[0]] = true; 16 | //for rest stuff 17 | for (int index = 1; index < n; index++) { 18 | for (int givenTarget = 1; givenTarget <= target ; givenTarget++) { 19 | bool notPick = dp[index - 1][givenTarget]; 20 | bool pick = false; 21 | if (givenTarget >= arr[index]) pick = dp[index - 1][givenTarget - arr[index]]; 22 | dp[index][givenTarget] = (pick or notPick); 23 | } 24 | } 25 | /* here the required ans is in this row dp[n - 1][target] , where target lies from 0 to totalSum but 26 | as we saw that there will be half values which occurs in both the sets at a time so for optimising we 27 | can use totalSum / 2 */ 28 | int miniAbsDiff = INT_MAX; 29 | for (int setFirst = 0; setFirst <= target / 2; setFirst++) { 30 | if (dp[n - 1][setFirst]) { 31 | miniAbsDiff = min(miniAbsDiff, abs((target - setFirst) - setFirst)); 32 | //here target - setFirst can be visualised as the second subset and setFirst is the first subset 33 | } 34 | } 35 | return miniAbsDiff; 36 | } 37 | 38 | int main() { 39 | int n; cin >> n; 40 | vector arr(n); 41 | for (int &i : arr) cin >> i; 42 | cout << "minSubsetSumDifference : " << minSubsetSumDifference(arr, n) << endl; 43 | return 0; 44 | 45 | } -------------------------------------------------------------------------------- /DP on Subsequences/Rod Cutting Problem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | 5 | /*recursion and memoization code - 6 | 7 | For Memoization - TC :O(N*N) & SC: O(N*N) + O(N) 8 | For Recursion - TC : >O(2^N) & SC: >O(N) */ 9 | 10 | int waysToCutRod(int part, vector &price, vector> &memo, int currLength) { 11 | if (part == 0) { 12 | return currLength * price[0]; 13 | } 14 | if (memo[part][currLength] != -1) return memo[part][currLength]; 15 | int notCut = waysToCutRod(part - 1, price, memo, currLength); 16 | int cut = INT_MIN; 17 | int currRodLength = part + 1; 18 | if (currRodLength <= currLength) cut = price[part] + waysToCutRod(part, price, memo, currLength - currRodLength); 19 | return memo[part][currLength] = max(cut, notCut); 20 | } 21 | 22 | 23 | /*tabulation approach */ 24 | int waysToCutRodTabul(vector &price, int n) { 25 | vector> memo(n, vector (n + 1, -1)); 26 | //for the base case 27 | for (int i = 0; i <= n; i++)memo[0][i] = i * price[0]; 28 | for (int part = 1; part < n; part++) { 29 | for (int currLength = 0; currLength <= n; currLength++) { 30 | int notCut = memo[part - 1][currLength]; 31 | int cut = INT_MIN; 32 | int currRodLength = part + 1; 33 | if (currRodLength <= currLength)cut = price[part] + memo[part][currLength - currRodLength]; 34 | memo[part][currLength] = max(cut, notCut); 35 | } 36 | } 37 | return memo[n - 1][n]; 38 | } 39 | 40 | 41 | /*space optimisation approach */ 42 | int waysToCutRodSpaceOpt(vector &price, int n) { 43 | vector prev(n + 1), curr(n + 1); 44 | //for the base case 45 | for (int i = 0; i <= n; i++)prev[i] = i * price[0]; 46 | for (int part = 1; part < n; part++) { 47 | for (int currLength = 0; currLength <= n; currLength++) { 48 | int notCut = prev[currLength]; 49 | int cut = INT_MIN; 50 | int currRodLength = part + 1; 51 | if (currRodLength <= currLength)cut = price[part] + curr[currLength - currRodLength]; 52 | curr[currLength] = max(cut, notCut); 53 | } 54 | prev = curr; 55 | } 56 | return prev[n]; 57 | } 58 | 59 | int cutRod(vector &price, int n) { 60 | 61 | //for memoization - 62 | // vector> memo(n, vector (n + 1, -1)); 63 | // int res = waysToCutRod(n - 1, price, memo, n); 64 | 65 | //for tabulation 66 | // int res = waysToCutRodTabul(price, n); 67 | 68 | //for space optimisation 69 | int res = waysToCutRodSpaceOpt(price, n); 70 | return res; 71 | } 72 | 73 | 74 | int main() { 75 | 76 | int totalLength ; 77 | cin >> totalLength; 78 | vector price(totalLength); 79 | for (int &i : price) cin >> i; 80 | cout << "Total Profit: " << cutRod(price, totalLength); 81 | return 0; 82 | 83 | } -------------------------------------------------------------------------------- /DP on Subsequences/Subset Sum Equals to Target.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //recursive solution TC - O(2^N) SC - O(N); 5 | bool checkForTheValidSubset(int currInd, int target, vector &arr) { 6 | if (target == 0) return true; 7 | if (currInd == 0) return arr[0] == target; 8 | int notPick = checkForTheValidSubset(currInd - 1, target, arr); 9 | int pick = false; 10 | if (target >= arr[currInd])pick = checkForTheValidSubset(currInd - 1, target - arr[currInd], arr); 11 | return (pick or notPick); 12 | } 13 | 14 | 15 | //memoisation approach - TC - O(N* target) SC - O(N*target)+O(N) 16 | bool checkForTheValidSubsetMemo(int currInd, int target, vector &arr, vector> &dp) { 17 | if (target == 0) return true; 18 | if (dp[currInd][target] != -1) return dp[currInd][target]; 19 | if (currInd == 0) return arr[0] == target; 20 | int notPick = checkForTheValidSubsetMemo(currInd - 1, target, arr, dp); 21 | int pick = false; 22 | if (target >= arr[currInd])pick = checkForTheValidSubsetMemo(currInd - 1, target - arr[currInd], arr, dp); 23 | return dp[currInd][target] = (pick or notPick); 24 | } 25 | 26 | // tabulation approach - TC - O(N* target) SC - O(N*target) 27 | bool checkForTheValidSubsetTabul(int n, int target, vector &arr) { 28 | vector> dp(n, vector (target + 1, false)); 29 | //for the first base case considering target as 0 30 | for (int i = 0 ; i < n; i++) dp[i][0] = true; 31 | //for the second base considering the index as 0 32 | if (arr[0] <= target) dp[0][arr[0]] = true; 33 | //for rest stuff 34 | for (int index = 1; index < n; index++) { 35 | for (int givenTarget = 1; givenTarget <= target ; givenTarget++) { 36 | bool notPick = dp[index - 1][givenTarget]; 37 | bool pick = false; 38 | if (givenTarget >= arr[index]) pick = dp[index - 1][givenTarget - arr[index]]; 39 | dp[index][givenTarget] = (pick or notPick); 40 | } 41 | } 42 | return dp[n - 1][target]; 43 | } 44 | 45 | 46 | //space optimised approach - 47 | bool checkForTheValidSubsetSpaceOptimise(int n, int target, vector &arr) { 48 | vector prev(target + 1, false), curr(target + 1, false); 49 | //for the first base case considering target as 0 50 | prev[0] = curr[0] = true; 51 | //for the second base considering the index as 0 52 | prev[arr[0]] = true; 53 | //for rest stuff 54 | for (int index = 1; index < n; index++) { 55 | for (int givenTarget = 1; givenTarget <= target ; givenTarget++) { 56 | bool notPick = prev[givenTarget]; 57 | bool pick = false; 58 | if (givenTarget >= arr[index]) pick = prev[givenTarget - arr[index]]; 59 | curr[givenTarget] = (pick or notPick); 60 | } 61 | prev = curr; 62 | } 63 | return prev[target]; 64 | } 65 | 66 | 67 | bool subsetSumToK(int n, int target, vector &arr) { 68 | vector> dp(n + 1, vector (target + 1, -1)); 69 | // int ans = checkForTheValidSubset(n - 1, target, arr); 70 | int ans = checkForTheValidSubsetMemo(n - 1, target, arr, dp); 71 | // int ans = checkForTheValidSubsetTabul(n, target, arr); 72 | // int ans = checkForTheValidSubsetSpaceOptimise(n, target, arr); 73 | return ans; 74 | } 75 | 76 | int main() { 77 | int size; 78 | cin >> size; 79 | vector arr(size); 80 | for (int &i : arr) cin >> i; 81 | int target; cin >> target; 82 | if (subsetSumToK(size, target, arr)) cout << "Is Valid Subsequence" << endl; 83 | else cout << "Is Invalid Subsequence" << endl; 84 | return 0; 85 | 86 | } -------------------------------------------------------------------------------- /DP on Subsequences/Target sum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //memoisation is the approach i am usign here , we can also use space optimised or tabulation here 5 | 6 | /*this question is exact similar to the tutorial 18 i.e., Count partitions with the given difference . instead of putting signs we 7 | have to just divide array in such a way so that the difference of both the subsets is equals to the target */ 8 | 9 | //code for dp memoisation approach 10 | int countPossibleSubsetsMemo(int ind, vector &nums, int target, vector> &memo) { 11 | //base case 12 | if (ind == 0) { 13 | if (target == 0 and nums[ind] == 0) return 2;//if both the condition satisfies then the answer will be 2 if the first index is 0 we have to include it too in our subset 14 | if (target == 0 or nums[ind] == target) return 1; 15 | return 0; 16 | } 17 | 18 | if (memo[ind][target] != -1) return memo[ind][target]; 19 | //as the question is on subsets then we can break down in terms of indices 20 | int pick = 0; 21 | if (nums[ind] <= target)pick = countPossibleSubsetsMemo(ind - 1, nums, target - nums[ind], memo); 22 | int notPick = countPossibleSubsetsMemo(ind - 1, nums, target, memo); 23 | return memo[ind][target] = pick + notPick; 24 | } 25 | 26 | 27 | 28 | int targetSum(int n, int d, vector &arr) { 29 | int target = 0; 30 | for (int i : arr) target += i; 31 | vector> memo(n , vector(target + 1, -1)); 32 | if (target - d < 0 or ((target - d) & 1)) return 0; 33 | /* 34 | lets say total sum will be Target now we know that for two subsets say s1,s2 - 35 | target = s1+s2 or s1 =target - s2, -------------- (1) 36 | on the therr hand in the question given that the difference of two required subsets will be D so, 37 | D= s1 - s2------------------(2) 38 | from eqn (1), 39 | D = target - s2 -s2 = target - 2s2 40 | hence s2 = (target - D)/2 so this will be our target and from the last problem we can observe that if we find find one subset 41 | then automatically 2nd is in our hand 42 | */ 43 | return countPossibleSubsetsMemo(n - 1, arr, (target - d) / 2, memo); 44 | } 45 | 46 | int main() { 47 | 48 | int n; cin >> n; 49 | int diff; cin >> diff; 50 | vector arr(n); 51 | for (int &i : arr) cin >> i; 52 | cout << "Number of Ways : " << targetSum(n, diff, arr) << endl; 53 | return 0; 54 | 55 | } -------------------------------------------------------------------------------- /DP on Subsequences/Unbounded Knapsack.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | /* Recursive + Memoisation code 5 | 6 | Recursive- TC - >O(2^N) , SC - >O(N) , because there can be the more than 2 choices for each index if anywhere required 7 | Memoisation - TC - O(N*maxWeight) , SC - O(N*maxWeight)+O(N) 8 | */ 9 | int giveMaxWeightMemo(int currHouse, vector &weight, vector &profit, int maxWeight, vector>&dp) { 10 | if (currHouse == 0) return (maxWeight / weight[0]) * profit[0]; 11 | /* -> if we reach the first index then if target if not 0 then according to the profit at first index we take the 12 | maxWeight/weight[0] for each we get the profit[0] so multiply it number of times 13 | */ 14 | if (dp[currHouse][maxWeight] != -1) return dp[currHouse][maxWeight]; 15 | int notPick = giveMaxWeightMemo(currHouse - 1, weight, profit, maxWeight, dp); 16 | int pick = -1e9; 17 | if (weight[currHouse] <= maxWeight) 18 | pick = profit[currHouse] + giveMaxWeightMemo(currHouse, weight, profit, maxWeight - weight[currHouse], dp); 19 | return dp[currHouse][maxWeight] = max(pick, notPick); 20 | } 21 | 22 | /*Tabulation approach*/ 23 | int giveMaxWeightTabu(vector &weight, vector &profit, int n, int &maxWeight) { 24 | // Write your code here 25 | vector> dp(n, vector(maxWeight + 1)); 26 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++)dp[0][fromWeight] = (fromWeight / weight[0]) * profit[0]; 27 | for (int currHouse = 1; currHouse < n; currHouse++) { 28 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++) { 29 | int notPick = dp[currHouse - 1][fromWeight]; 30 | int pick = -1e9; 31 | if (weight[currHouse] <= fromWeight) 32 | pick = profit[currHouse] + dp[currHouse][fromWeight - weight[currHouse]]; 33 | dp[currHouse][fromWeight] = max(pick, notPick); 34 | } 35 | } 36 | return dp[n - 1][maxWeight]; 37 | } 38 | 39 | 40 | int giveMaxWeightSpaceOpt(vector &weight, vector &profit, int n, int &maxWeight) { 41 | // Write your code here 42 | vector prev(maxWeight + 1), curr(maxWeight + 1); 43 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++)prev[fromWeight] = (fromWeight / weight[0]) * profit[0]; 44 | for (int currHouse = 1; currHouse < n; currHouse++) { 45 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++) { 46 | int notPick = prev[fromWeight]; 47 | int pick = -1e9; 48 | if (weight[currHouse] <= fromWeight) 49 | pick = profit[currHouse] + curr[fromWeight - weight[currHouse]]; 50 | curr[fromWeight] = max(pick, notPick); 51 | } 52 | prev = curr; 53 | } 54 | return prev[maxWeight]; 55 | } 56 | 57 | /*...................Most optimal approach using single array optimisation...................*/ 58 | int mostOptimalResultant(vector &weight, vector &profit, int n, int &maxWeight) { 59 | // Write your code here 60 | vector prev(maxWeight + 1); 61 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++)prev[fromWeight] = (fromWeight / weight[0]) * profit[0]; 62 | for (int currHouse = 1; currHouse < n; currHouse++) { 63 | for (int fromWeight = 0; fromWeight <= maxWeight; fromWeight++) { 64 | int notPick = prev[fromWeight]; 65 | int pick = -1e9; 66 | if (weight[currHouse] <= fromWeight) 67 | pick = profit[currHouse] + prev[fromWeight - weight[currHouse]]; 68 | prev[fromWeight] = max(pick, notPick); 69 | } 70 | } 71 | return prev[maxWeight]; 72 | } 73 | 74 | 75 | 76 | //main knapsack function 77 | int knapsack(vector &weight, vector &profit, int n, int &maxWeight) { 78 | // Write your code here 79 | // vector> dp(n, vector(maxWeight + 1, -1)); 80 | //memoisation 81 | // int maxCost = giveMaxWeightMemo(n - 1, weight, profit, maxWeight, dp); 82 | //tabulation 83 | // int maxCost = giveMaxWeightTabu(weight, profit, n, maxWeight); 84 | //space optimisation 85 | // int maxCost = giveMaxWeightSpaceOpt(weight, profit, n, maxWeight); 86 | //most optimal result 87 | int maxCost = mostOptimalResultant(weight, profit, n, maxWeight); 88 | return maxCost; 89 | } 90 | 91 | 92 | 93 | int main() { 94 | int n; cin >> n; 95 | int maxWeight; cin >> maxWeight; 96 | vectorweight(n), profit(n); 97 | for (int &i : profit)cin >> i; 98 | for (int &i : weight)cin >> i; 99 | cout << "Max profit : " << knapsack(weight, profit, n, maxWeight) << endl; 100 | return 0; 101 | 102 | } -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # [DP Beginner to Advanced](https://github.com/singhkunal01/Dynamic-Programming) 👨🏻‍💻 2 | 3 | - It contains all the codes which i coded during the learning of Dynamic Programming With All Possible Approaches Like - 4 | > Recursion \ 5 | > Memoization \ 6 | > Tabulation \ 7 | > Space Optimisation (Wherever Needed) 8 | 9 | | Type Of Questions/S-No. | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 10 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |:---: | :---: | :---: | 11 | | **1D - DP on Jump Patterns** | [DP Fibonacci](https://bit.ly/3PM5DP9) | [Frog Jumps for 2 steps](https://bit.ly/3wmV9yU) | [Frog Jumps for K steps](https://bit.ly/3Cosy01) | [Horse Robber 2](https://bit.ly/3wqzshv) | [Maximum sum of non-adjacent elements(House Robber)](https://bit.ly/3PF8n0Q) | [N-stairs](https://bit.ly/3KeQ2GQ) | - | - | - | - | - | - | 12 | | **2D - DP on Grid** | [Grid Unique Paths 2](https://bit.ly/3Tce49t) | [Grid Unique Paths](https://bit.ly/3chP3cc) | [Minimum Falling Path Sum](https://bit.ly/3dPaBxm) | [Minimum Path Sum](https://bit.ly/3AIQqtT) | [Ninja Training](https://bit.ly/3AIQzNX) | [Triangle](https://bit.ly/3UWvlo8) | - | - | - | - | - | - | 13 | | **2D - DP on Subsequences** | [0-1 Knapsack](https://bit.ly/3AGvXWO) | [Coin change 2](https://bit.ly/3KeYHJj) |[Count Partitions With Given Difference](https://bit.ly/3bYGS4y) | [Count Subset with sum K](https://bit.ly/3SRVyCZ) | [Minimum Coins](https://bit.ly/3CtzxVA) | [Partition Equal subset sum](https://bit.ly/3CJBHAD) | [Partition a set into two subsets such that the difference of subset sums is minimum](https://bit.ly/3AGv14K)| [Rod Cutting Problem](https://bit.ly/3AJ1oQ7) | [Subset Sum Equals to Target](https://bit.ly/3R4dc4J) | [Target sum](https://bit.ly/3PMSYM2) | [Unbounded Knapsack](https://bit.ly/3AlfMwI) | 14 | | **2D - DP on Strings** | [Longest Common Subsequence](https://bit.ly/3dTbvZR) | [Print Longest Common Subsequence](https://bit.ly/3corIFM) | [Longest Common Substring](https://bit.ly/3PFZzYF) |[Longest Palindromic Substring](https://bit.ly/3KkQ7IX) | [Minimum Insertions To convert a string into Palindromic String](https://bit.ly/3wHR48O) | [Minimum Number of Insertion-Deletions to Make both strings Equal](https://bit.ly/3Kwt5Pw) | [Shortest Common Supersequence](https://bit.ly/3pUyZ3n) | (String Matching) [Distinct Subsequences](https://bit.ly/3RkIe8N) | (String Matching) [Edit Distance](https://bit.ly/3x2V18j) | (String Matching) [Wildcard Matching](https://bit.ly/3AxhcUR) | -| 15 | | **2D - DP on Stocks** | [Best Time to Buy & sell stock](https://bit.ly/3KVu9Na) | [Best Time to Buy & sell stocks 2](https://bit.ly/3RGyc1J) | [Best Time to Buy & sell stocks 3](https://bit.ly/3TJumGX) |[Best Time to Buy & sell stocks 4](https://bit.ly/3APhDds) | [Best Time to Buy & Sell stock with Cooldown](https://bit.ly/3eqcctV) | [Minimum Number of Insertion-Deletions to Make both strings Equal](https://bit.ly/3qaCkLZ) | - | - | - | - | - | 16 | | **2D - DP on Increasing Subsequences** | [Longest Increasing Subsequence(LIS)](https://bit.ly/3AVDO1H) | [Printing the Longest Increasing Subsequence(LIS)](https://bit.ly/3BuGu7N) | [Longest Increasing Subsequence(LIS)-Binary Search](https://bit.ly/3Qw2l2X) | [Largest Divisible Subset(LIS)](https://bit.ly/3xd7JkB) | [Longest String chain](https://bit.ly/3BwAcom) | [Longest Bitonic Subsequence](https://bit.ly/3qLf5Zj) | [Number of Longest Increasing Subsequences](https://bit.ly/3B9iplL) | - | - | - | - | 17 | | **2D - DP On Partitions(MCM) Pattern** | [Matrix Chain Multiplication Memoization](https://bit.ly/3fELMF6) | [Matrix Chain Multiplication Tabulation](https://bit.ly/3Rt1Bw8) | [Minimum cost to cut the Stick](https://bit.ly/3dXWK8t) | [Burst Balloons](https://bit.ly/3LZ01ke) | [Boolean Evaluation](https://bit.ly/3y9Jqo9) | [Palindrome Partition](https://bit.ly/3C1TAbF) | [Partition array for Maximum sum](https://bit.ly/3rp2Vp9) | [Maximum rectangle area with all 1s](https://bit.ly/3RoAlic) |[Count square submatrices with all 1s](https://bit.ly/3dUcbyA) | - | - | 18 | | **3D - DP on Grid** | (Jump Pattern) [Cherry Pickup](https://bit.ly/3dMhEXz) | (On stocks) [Best Time to Buy & sell stocks 2](https://bit.ly/3RGyc1J) | (On stocks) [Best Time to Buy & sell stocks 3](https://bit.ly/3TJumGX) |- | - | - | - | - | - | - | - | 19 | 20 |

< / > with ❤️ by Kunal Singh

21 | 22 | ```diff 23 | @@ Star This Repository if You Like the codes & Explanation 🌟@@ 24 | ``` 25 | --------------------------------------------------------------------------------