├── Dynamic Programming ├── 1D DP │ ├── 15 - Geek Jump │ │ ├── README.md │ │ └── Geek Jump.cpp │ ├── 20 - Jump Game │ │ ├── README.md │ │ └── Jump Game.cpp │ ├── 21 - Jump Game II │ │ ├── README.md │ │ └── Jump Game II.cpp │ ├── 23 - Coin Change │ │ ├── README.md │ │ ├── 23.1 - Coin Change (Without Sorting).cpp │ │ └── 23.2 - Coin Change (With Sorting).cpp │ ├── 30 - Decode Ways │ │ └── README.md │ ├── 31 - Decode Ways II │ │ └── README.md │ ├── 6 - Climbing Stairs │ │ ├── README.md │ │ └── Climbing Stairs.cpp │ ├── 8 - House Robber │ │ ├── README.md │ │ └── House Robber.cpp │ ├── 9 - House Robber II │ │ ├── README.md │ │ └── House Robber II.cpp │ ├── 1 - Fibonacci Number │ │ └── README.md │ ├── 26 - Dice Combinations │ │ ├── README.md │ │ └── Dice Combinations.cpp │ ├── 27 - Combination Sum IV │ │ ├── README.md │ │ ├── 27.1 - Combination Sum IV (Without Sorting).cpp │ │ └── 27.2 - Combination Sum IV (With Sorting).cpp │ ├── 4 - Tribonacci Number │ │ ├── README.md │ │ └── Tribonacci Number.cpp │ ├── 16 - Geek Jump With K Steps │ │ ├── README.md │ │ └── Geek Jump With K Steps.cpp │ ├── 0 - Sum of First N Natural Numbers │ │ └── README.md │ ├── 13 - Maximize The Cut Segments │ │ └── README.md │ ├── 7 - Minimum Cost Climbing Stairs │ │ ├── README.md │ │ └── Minimum Cost Climbing Stairs.cpp │ ├── 24 - Perfect Squares │ │ └── Perfect Squares.cpp │ ├── 25 - Integer Break │ │ └── Integer Break.cpp │ ├── 28 - Removing Digits │ │ └── Removing Digits.cpp │ ├── 10 - Solving Questions With Brainpower │ │ └── Solving Questions With Brainpower.cpp │ ├── 12 - Minimum Steps To Minimize N As Per Given Condition │ │ ├── 12.1 - Minimum Steps To Minimize N As Per Given Condition.cpp │ │ └── 12.2 - Minimum Steps To Minimize N As Per Given Condition (Loop Version).cpp │ ├── 11 - Count Ways To Build Good Strings │ │ └── Count Ways To Build Good Strings.cpp │ ├── 17 - Climbing Stairs II │ │ └── 17.2 - Climbing Stairs II (Loop Version).cpp │ ├── 3 - Consecutive Ones Not Allowed │ │ └── Consecutive Ones Not Allowed.cpp │ ├── 18 - Taking Maximum Energy From The Mystic Dungeon │ │ └── Taking Maximum Energy From The Mystic Dungeon.cpp │ ├── 5 - Count Number of Hops │ │ └── Count Number of Hops.cpp │ ├── 22 - Maximum Number Of Jumps To Reach The Last Index │ │ └── Maximum Number Of Jumps To Reach The Last Index.cpp │ ├── 14 - Minimum Cost For Tickets │ │ ├── 14.1 - Minimum Cost For Tickets (Linear Search).cpp │ │ └── 14.2 - Minimum Cost For Tickets (Binary Search).cpp │ ├── 2 - Filling Bucket │ │ └── Filling Bucket.cpp │ └── 19 - Minimum Number of Coins for Fruits │ │ └── 19.2 - Minimum Number of Coins for Fruits (Enhanced).cpp ├── Introduction To DP │ ├── README.md │ └── Notes.pdf ├── Subarrays DP │ └── new_problem_cf-1899_C ├── Multi Dimensional DP │ ├── 4 - Unique Paths │ │ └── README.md │ ├── 3 - Paths To Reach Origin │ │ └── README.md │ ├── 1 - Consecutive Ones Not Allowed │ │ └── README.md │ ├── 38 - Number of Increasing Paths In Grid.cpp │ ├── 31 - Soup Servings.cpp │ ├── 15 - nCr.cpp │ ├── 30 - Ways To Express an Integer as Sum of Powers.cpp │ ├── 37.2 - Longest Increasing Path In A Matrix.cpp │ └── 24 - Paint House.cpp ├── Graph DP │ ├── README.md │ ├── 3 - Cheapest Flights Within K Stops.cpp │ └── 2 - Parallel Courses III.cpp ├── LIS DP │ ├── 12 - Minimum Number of Removals to Make Mountain Array.cpp │ ├── 19 - Number of Longest Increasing Subsequences.cpp │ ├── 4 - Print Longest Increasing Subsequence.cpp │ ├── 11 - Longest Bitonic Subsequence.cpp │ └── 5 - Largest Divisible Subset.cpp ├── String DP │ ├── 7 - Print Longest Common Subsequence.cpp │ ├── 8 - Print Longest Palindromic Subsequence.cpp │ ├── 2 - Longest Common Substring.cpp │ ├── 9 - Print Longest Common Substring.cpp │ ├── 15 - Shortest Common Supersequence.cpp │ └── 11 - Count Palindromic Substrings.cpp ├── Tree DP │ ├── 3 - Linked List in Binary Tree.cpp │ └── 1 - House Robber III.cpp └── Partition DP │ ├── 3 - Count Digit Groupings Of A Number.cpp │ └── 12 - Minimum Cost To Split An Array.cpp ├── README.md ├── BEST - Solving Real World Problem └── README.md ├── Stack └── Reverse Substrings Between Each Pair of Parentheses.cpp ├── Backtracking ├── Subset Sums.cpp ├── Power Set.cpp └── Subsets I.cpp ├── String ├── Reverse Words in a String III.cpp └── Minimum Number Of Steps To Make Two Strings Anagram.cpp ├── Greedy └── Divide Array Into Arrays With Max Difference.cpp ├── Advanced └── Tree │ └── Fenwick Tree (BIT) │ └── Range Sum Query - Immutable.cpp ├── Array └── Rearrange Array Elements By Sign.cpp └── Bit Manipulation └── Check If Bitwise OR Has Trailing Zeros.cpp /Dynamic Programming/1D DP/15 - Geek Jump/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/mnDFWKfPBIM) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/20 - Jump Game/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/R9GpRY4AEKM) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/Introduction To DP/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/CZNqEb2-Ncc) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/Subarrays DP/new_problem_cf-1899_C: -------------------------------------------------------------------------------- 1 | https://codeforces.com/problemset/problem/1899/C 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/21 - Jump Game II/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/FGNEXmgXmjQ) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/23 - Coin Change/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/xoyBhDvBY6U) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/30 - Decode Ways/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/RC4HoGHqJaE) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/31 - Decode Ways II/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/7aIua6-Rqz0) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/6 - Climbing Stairs/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/kj4-U9TpppY) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/8 - House Robber/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/bj2axCoSfFk) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/9 - House Robber II/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/5C2BEF2pk7k) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/1 - Fibonacci Number/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/rtq5jRtnRCw) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/26 - Dice Combinations/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/ZMVMszm_ocE) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/27 - Combination Sum IV/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/gHzidaRtlTI) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/4 - Tribonacci Number/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/jviOM3KWh9I) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/16 - Geek Jump With K Steps/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/qZg_ySDOwU0) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/0 - Sum of First N Natural Numbers/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/v0UPf4s_0FI) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/13 - Maximize The Cut Segments/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/xwKl5He8P5c) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/7 - Minimum Cost Climbing Stairs/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/30UaO_r0Jp8) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/4 - Unique Paths/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/duArKX95koE) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/3 - Paths To Reach Origin/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/kSD2l-synp8) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/1 - Consecutive Ones Not Allowed/README.md: -------------------------------------------------------------------------------- 1 | ## [VIDEO LECTURE LINK](https://youtu.be/J86qzhYxG8Y) 2 | -------------------------------------------------------------------------------- /Dynamic Programming/Introduction To DP/Notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hiren-j/dsaAffection/HEAD/Dynamic Programming/Introduction To DP/Notes.pdf -------------------------------------------------------------------------------- /Dynamic Programming/Graph DP/README.md: -------------------------------------------------------------------------------- 1 | ***DP in Graphs be like: You're solving the question and watching your code getting successfully submitted 😎, and then you realized that you did Dynamic Programming in it 🤪. So, moral of the story is don't be afraid of Graph DP 💪. It's because most of the times you may feel like Graph and DP are the same, and that's because the solution thinking naturally leads you to it 🧠.*** 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 👉 𝐌𝐲 𝐃𝐲𝐧𝐚𝐦𝐢𝐜 𝐏𝐫𝐨𝐠𝐫𝐚𝐦𝐦𝐢𝐧𝐠 𝐒𝐞𝐫𝐢𝐞𝐬 𝐜𝐨𝐯𝐞𝐫𝐢𝐧𝐠 𝟏𝟐 𝐏𝐀𝐓𝐓𝐄𝐑𝐍𝐒 — 𝐧𝐨𝐰 𝐡𝐚𝐬 𝐯𝐢𝐝𝐞𝐨 𝐥𝐞𝐜𝐭𝐮𝐫𝐞𝐬 𝐚𝐯𝐚𝐢𝐥𝐚𝐛𝐥𝐞! [𝐏𝐋𝐀𝐘𝐋𝐈𝐒𝐓 𝐋𝐈𝐍𝐊](https://opener.one/yt/q4fd5s) 2 | 3 | # 𝙒𝙝𝙖𝙩 𝙮𝙤𝙪 𝙝𝙖𝙫𝙚 𝙩𝙤 𝙙𝙤? 4 | 5 | ➡️ 𝙊𝙥𝙚𝙣 𝙖 𝙘𝙤𝙣𝙨𝙤𝙡𝙚 𝙥𝙧𝙤𝙜𝙧𝙖𝙢 𝙛𝙧𝙤𝙢 𝙖 𝙛𝙤𝙡𝙙𝙚𝙧, 𝙘𝙤𝙥𝙮 𝙩𝙝𝙚 𝙘𝙤𝙙𝙚 𝙖𝙣𝙙 𝙥𝙖𝙨𝙩𝙚 𝙞𝙩 𝙞𝙣 𝙖𝙣 𝙤𝙣𝙡𝙞𝙣𝙚 𝙘++ 𝙘𝙤𝙢𝙥𝙞𝙡𝙚𝙧 𝙖𝙣𝙙 𝙩𝙝𝙚𝙣 𝙚𝙭𝙚𝙘𝙪𝙩𝙚 𝙞𝙩. 6 | 7 | ➡️ 𝙏𝙝𝙤𝙨𝙚 𝙪𝙨𝙚𝙧-𝙞𝙣𝙩𝙚𝙧𝙖𝙘𝙩𝙞𝙫𝙚 𝙘𝙤𝙣𝙨𝙤𝙡𝙚 𝙖𝙥𝙥𝙨 𝙬𝙚𝙧𝙚 𝙘𝙧𝙚𝙖𝙩𝙚𝙙 𝙖 𝙮𝙚𝙖𝙧 𝙖𝙜𝙤, 𝙨𝙤 𝙛𝙤𝙧 𝙖 𝙢𝙤𝙧𝙚 𝙧𝙚𝙡𝙚𝙫𝙖𝙣𝙩 𝙧𝙚𝙫𝙞𝙚𝙬, 𝙥𝙡𝙚𝙖𝙨𝙚 𝙥𝙧𝙚𝙛𝙚𝙧 𝙩𝙝𝙚 𝙡𝙖𝙩𝙚𝙨𝙩 𝙪𝙥𝙙𝙖𝙩𝙚𝙙 𝙛𝙞𝙡𝙚. 8 | 9 | ➡️ 𝙊𝙥𝙚𝙣 𝙩𝙝𝙚 [𝘿𝙮𝙣𝙖𝙢𝙞𝙘 𝙋𝙧𝙤𝙜𝙧𝙖𝙢𝙢𝙞𝙣𝙜](https://github.com/hiren-j/dsaAffection/tree/C%2B%2B/Dynamic%20Programming) 𝙛𝙤𝙡𝙙𝙚𝙧 — 𝙞𝙩 𝙬𝙖𝙨 𝙩𝙝𝙚 𝙢𝙤𝙨𝙩 𝙧𝙚𝙘𝙚𝙣𝙩𝙡𝙮 𝙪𝙥𝙙𝙖𝙩𝙚𝙙. 10 | 11 | ➡️ 𝙊𝙛 𝙘𝙤𝙪𝙧𝙨𝙚, 𝙜𝙤 𝙖𝙝𝙚𝙖𝙙 𝙩𝙤 𝙚𝙣𝙟𝙤𝙮 𝙩𝙝𝙤𝙨𝙚 𝙤𝙡𝙙 𝙪𝙨𝙚𝙧-𝙞𝙣𝙩𝙚𝙧𝙖𝙘𝙩𝙞𝙫𝙚 𝙘𝙤𝙣𝙨𝙤𝙡𝙚 𝙖𝙥𝙥𝙡𝙞𝙘𝙖𝙩𝙞𝙤𝙣𝙨! 12 | -------------------------------------------------------------------------------- /BEST - Solving Real World Problem/README.md: -------------------------------------------------------------------------------- 1 | 🎉 **Title:** Blindfolded Solving & Creating Patterns In Rubik Pyramid Through DSA - Best Problem I've Ever Solved (Real World Problem) 💡🎯🔥 2 | 3 | 🧩 **Initial Note:** This video showcases why DSA is my all-time favorite subject. Programming helped me improve my problem-solving skills, and it was these skills that allowed me to solve this real-world problem and I feel its the best problem that I have ever solved! Literally a huge thanks to DSA for sharpening my mind and enabling me to tackle such challenge! And I specially want to thank [LeetCode](https://leetcode.com/u/leetcode/) for providing such a great platform to improve problem-solving skills. 4 | 5 | 🤔 **Question:** How did I achieve this? 6 | 7 | 👉🏻 **Intuition Overview:** At first, I focused on gaining experience for faster movements. I was just figuring out the best ways to move the blocks, thinking about things like finger placement and speed, without worrying about anything else. Initially, I just wanted to build muscle memory. Within the first 5 days, I developed a brute force solution through my thought process on **permutations and backtracking.** Over time, I refined my observations and gained the ability to create intricate patterns. The real challenge came when I aimed to do it **blindfolded.** Although it felt impossible initially, persistent practice turned this goal into reality. The experience mirrored coding’s power to train your mind to tackle **any problem with precision.** 8 | 9 | 🎥 [**Click to Watch the Video**](https://www.linkedin.com/posts/hirenjoshi1630_reallifeproblem-solution-datastructuresalgorithms-activity-7185150609266790400-ZbEr?utm_source=share&utm_medium=member_desktop) 10 | 11 | 😊 **Final Note:** Practice brings progress. Stay consistent, keep trying, and unlock your potential! Let this inspire you to dive into the world of programming. 12 | 13 | #LeetCode #GFG #ThanksToLeetCode 14 | #ProblemSolving #DSA 15 | #RubikPyramidChallenge #ProgrammingSkills 16 | #Backtracking #Permutation #CodingJourney 17 | -------------------------------------------------------------------------------- /Dynamic Programming/LIS DP/12 - Minimum Number of Removals to Make Mountain Array.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum number of elements to remove to make an array a mountain array ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the minimum number of elements to remove to make the given array a mountain array, using 1D tabulation - O(N*N) & O(N) 8 | int minimumMountainRemovals(vector& nums) { 9 | int n = nums.size(); 10 | 11 | vector LIS(n, 1), LDS(n, 1); 12 | 13 | // Find the length of the LIS of each index 14 | for(int index = 0; index < n; ++index) 15 | for(int prevIndex = 0; prevIndex < index; ++prevIndex) 16 | if(nums[prevIndex] < nums[index]) 17 | LIS[index] = max(LIS[index], LIS[prevIndex] + 1); 18 | 19 | // Find the length of the LDS of each index 20 | for(int index = n-1; index >= 0; --index) 21 | for(int nextIndex = n-1; nextIndex > index; --nextIndex) 22 | if(nums[nextIndex] < nums[index]) 23 | LDS[index] = max(LDS[index], LDS[nextIndex] + 1); 24 | 25 | int maxLenBitonic = 0; 26 | 27 | // If the strictly increasing and strictly decreasing subsequence of each index exists then update the bitonic length by the maximum value 28 | for(int index = 0; index < n; ++index) 29 | if(LIS[index] > 1 && LDS[index] > 1) 30 | maxLenBitonic = max(maxLenBitonic, LIS[index] + LDS[index] - 1); 31 | 32 | return n - maxLenBitonic; 33 | } 34 | }; 35 | 36 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 37 | 38 | Topics: Array | Binary Search | Dynamic Programming | Greedy 39 | Link : https://leetcode.com/problems/minimum-number-of-removals-to-make-mountain-array/description/ 40 | -------------------------------------------------------------------------------- /Dynamic Programming/LIS DP/19 - Number of Longest Increasing Subsequences.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the number of longest increasing subsequences. Notice that the sequence has to be strictly increasing ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the number of longest increasing subsequences, using 1D tabulation - O(N*N) & O(N) 8 | int findNumberOfLIS(vector& nums) { 9 | int n = nums.size(); 10 | 11 | vector dp(n, 1); // dp[index] represents the length of the LIS ending at that index 12 | vector count(n, 1); // count[index] represents the count of the LIS ending at that index 13 | 14 | for(int index = 0; index < n; ++index) { 15 | for(int prevIndex = 0; prevIndex < index; ++prevIndex) { 16 | if(nums[prevIndex] < nums[index]) { 17 | if(dp[prevIndex] + 1 == dp[index]) { 18 | count[index] += count[prevIndex]; 19 | } 20 | else if(dp[prevIndex] + 1 > dp[index]) { 21 | dp[index] = max(dp[index], 1 + dp[prevIndex]); 22 | count[index] = count[prevIndex]; 23 | } 24 | } 25 | } 26 | } 27 | 28 | int lengthOfLIS = *max_element(begin(dp), end(dp)); 29 | int countOfLIS = 0; 30 | 31 | // Iterate and count the total number of LIS 32 | for(int index = 0; index < n; ++index) { 33 | if(dp[index] == lengthOfLIS) { 34 | countOfLIS += count[index]; 35 | } 36 | } 37 | 38 | return countOfLIS; 39 | } 40 | }; 41 | 42 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 43 | 44 | Topics: Array | Dynamic Programming 45 | Link : https://leetcode.com/problems/number-of-longest-increasing-subsequence/description/ 46 | -------------------------------------------------------------------------------- /Dynamic Programming/String DP/7 - Print Longest Common Subsequence.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the longest common subsequence of s1 and s2 ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the LCS of given strings, using 2D tabulation - O(N*M) & O(N*M) 8 | string getLCS(string& s1, string& s2) { 9 | int n = s1.size(), m = s2.size(); 10 | 11 | // 2D DP table 12 | vector> dp(n + 1, vector(m + 1, 0)); 13 | 14 | // Find the length of the LCS of s1 and s2 15 | for(int i = 1; i <= n; ++i) { 16 | for(int j = 1; j <= m; ++j) { 17 | if(s1[i - 1] == s2[j - 1]) 18 | dp[i][j] = 1 + dp[i-1][j-1]; 19 | else 20 | dp[i][j] = max(dp[i-1][j], dp[i][j-1]); 21 | } 22 | } 23 | 24 | // Stores the result string 25 | string LCS; 26 | 27 | int i = n, j = m; 28 | 29 | while(i > 0 && j > 0) { 30 | // If both the letters match 31 | if(s1[i - 1] == s2[j - 1]) { 32 | LCS.push_back(s1[i - 1]); 33 | i = i - 1; 34 | j = j - 1; 35 | } 36 | // Else when both the letters don't match 37 | else { 38 | if(dp[i - 1][j] > dp[i][j - 1]) { 39 | i = i - 1; 40 | } 41 | else { 42 | j = j - 1; 43 | } 44 | } 45 | } 46 | 47 | // Reverse the string to get the actual order of the LCS 48 | reverse(begin(LCS), end(LCS)); 49 | 50 | // Return the result string 51 | return LCS; 52 | } 53 | }; 54 | 55 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 56 | 57 | Topics: String | Dynamic Programming 58 | Links : https://leetcode.com/problems/longest-common-subsequence/ 59 | https://github.com/hiren-j/dsaAffection/blob/C%2B%2B/Dynamic%20Programming/String%20DP/Longest%20Common%20Subsequence.cpp 60 | -------------------------------------------------------------------------------- /Dynamic Programming/String DP/8 - Print Longest Palindromic Subsequence.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the longest palindromic subsequence of given string ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the LPS of given string, using 2D tabulation - O(N*M) & O(N*M) 8 | int getLPS(string& s1) { 9 | int n = s1.size(); 10 | string s2 = s1; 11 | reverse(begin(s2), end(s2)); 12 | 13 | // 2D DP table 14 | vector> dp(n + 1, vector(n + 1, 0)); 15 | 16 | // Find the length of the LCS of s1 and s2 17 | for(int i = 1; i <= n; ++i) { 18 | for(int j = 1; j <= n; ++j) { 19 | if(s1[i - 1] == s2[j - 1]) 20 | dp[i][j] = 1 + dp[i-1][j-1]; 21 | else 22 | dp[i][j] = max(dp[i-1][j], dp[i][j-1]); 23 | } 24 | } 25 | 26 | // Stores the result string 27 | string LPS; 28 | 29 | int i = n, j = n; 30 | 31 | while(i > 0 && j > 0) { 32 | // If both the letters match 33 | if(s1[i - 1] == s2[j - 1]) { 34 | LPS.push_back(s1[i - 1]); 35 | i = i - 1; 36 | j = j - 1; 37 | } 38 | // Else when both the letters don't match 39 | else { 40 | if(dp[i - 1][j] > dp[i][j - 1]) { 41 | i = i - 1; 42 | } 43 | else { 44 | j = j - 1; 45 | } 46 | } 47 | } 48 | 49 | // Reverse the string to get the actual order of the LPS 50 | reverse(begin(LPS), end(LPS)); 51 | 52 | // Return the result string 53 | return LPS; 54 | } 55 | }; 56 | 57 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 58 | 59 | Topics: String | Dynamic Programming 60 | Links : https://leetcode.com/problems/longest-palindromic-subsequence/description/ 61 | https://github.com/hiren-j/dsaAffection/blob/C%2B%2B/Dynamic%20Programming/String%20DP/Longest%20Palindromic%20Subsequence.cpp 62 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/24 - Perfect Squares/Perfect Squares.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the least number of perfect square numbers that sums to N ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(sqrt(N)^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n == 0) 9 | return 0; 10 | 11 | int minSquares = INT_MAX; 12 | 13 | for(int i = 1; i*i <= n; ++i) { 14 | int nextSquares = solveWithoutMemo(n - i*i); 15 | minSquares = min(minSquares, nextSquares + 1); 16 | } 17 | 18 | return minSquares; 19 | } 20 | 21 | // O(sqrt(N)*N) & O(2*N) 22 | int solveWithMemo(vector& dp, int n) { 23 | if(n == 0) 24 | return 0; 25 | 26 | if(dp[n] != -1) 27 | return dp[n]; 28 | 29 | int minSquares = INT_MAX; 30 | 31 | for(int i = 1; i*i <= n; ++i) { 32 | int nextSquares = solveWithMemo(dp, n - i*i); 33 | minSquares = min(minSquares, nextSquares + 1); 34 | } 35 | 36 | return dp[n] = minSquares; 37 | } 38 | 39 | public: 40 | int numSquares(int n) { 41 | vector dp(n + 1, -1); 42 | return solveWithMemo(dp, n); 43 | } 44 | }; 45 | 46 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 47 | 48 | class BottomUp { 49 | public: 50 | // O(N*sqrt(N)) & O(1*N) : Where N = given_n 51 | int numSquares(int given_n) { 52 | vector dp(given_n + 1, -1); 53 | dp[0] = 0; 54 | 55 | for(int n = 1; n <= given_n; ++n) { 56 | int minSquares = INT_MAX; 57 | 58 | for(int i = 1; i*i <= n; ++i) { 59 | int nextSquares = dp[n - i*i]; 60 | minSquares = min(minSquares, nextSquares + 1); 61 | } 62 | 63 | dp[n] = minSquares; 64 | } 65 | 66 | return dp[given_n]; 67 | } 68 | }; 69 | 70 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 71 | 72 | Topics: Math | Dynamic Programming 73 | Link : https://leetcode.com/problems/perfect-squares/description/ 74 | -------------------------------------------------------------------------------- /Dynamic Programming/String DP/2 - Longest Common Substring.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the length of the longest common substring of given strings ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // #1 Method to find the length of the longest common substring, using 2D tabulation - O(N*M) & O(N*M) 8 | int longestCommonSubstring_V1(string& s1, string& s2, int n, int m) { 9 | // 2D DP table 10 | vector> dp(n + 1, vector(m + 1)); 11 | 12 | int maxLength = 0; 13 | 14 | for(int i = 1; i <= n; ++i) { 15 | for(int j = 1; j <= m; ++j) { 16 | // If both the letters match 17 | if(s1[i - 1] == s2[j - 1]) { 18 | dp[i][j] = 1 + dp[i - 1][j - 1]; 19 | } 20 | // Else when both the letters don't match 21 | else { 22 | dp[i][j] = 0; 23 | } 24 | maxLength = max(maxLength, dp[i][j]); 25 | } 26 | } 27 | 28 | return maxLength; 29 | } 30 | 31 | // #2 Method to find the length of the longest common substring, using 1D tabulation - O(N*M) & O(M) 32 | int longestCommonSubstring_V2(string& s1, string& s2, int n, int m) { 33 | // 1D DP tables 34 | vector prevRow(m + 1), currRow(m + 1); 35 | 36 | int maxLength = 0; 37 | 38 | for(int i = 1; i <= n; ++i) { 39 | for(int j = 1; j <= m; ++j) { 40 | // If both the letters match 41 | if(s1[i - 1] == s2[j - 1]) { 42 | currRow[j] = 1 + prevRow[j - 1]; 43 | } 44 | // Else when both the letters don't match 45 | else { 46 | currRow[j] = 0; 47 | } 48 | maxLength = max(maxLength, currRow[j]); 49 | } 50 | prevRow = currRow; 51 | } 52 | 53 | return maxLength; 54 | } 55 | }; 56 | 57 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 58 | 59 | Topics: String | Dynamic Programming 60 | Link : https://www.geeksforgeeks.org/problems/longest-common-substring1452/1 61 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/25 - Integer Break/Integer Break.cpp: -------------------------------------------------------------------------------- 1 | // Code to break the given n into the sum of k positive integers, where k >= 2, and maximize the product of those integers ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(N^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n <= 2) 9 | return 1; 10 | 11 | int maxProduct = 1; 12 | 13 | for(int num = 1; num < n; ++num) { 14 | int nextProduct = max(n - num, solveWithoutMemo(n - num)); 15 | maxProduct = max(maxProduct, nextProduct * num); 16 | } 17 | 18 | return maxProduct; 19 | } 20 | 21 | // O(N*N) & O(2*N) 22 | int solveWithMemo(vector& dp, int n) { 23 | if(n <= 2) 24 | return 1; 25 | 26 | if(dp[n] != -1) 27 | return dp[n]; 28 | 29 | int maxProduct = 1; 30 | 31 | for(int num = 1; num < n; ++num) { 32 | int nextProduct = max(n - num, solveWithMemo(dp, n - num)); 33 | maxProduct = max(maxProduct, nextProduct * num); 34 | } 35 | 36 | return dp[n] = maxProduct; 37 | } 38 | 39 | public: 40 | int integerBreak(int n) { 41 | vector dp(n + 1, -1); 42 | return solveWithMemo(dp, n); 43 | } 44 | }; 45 | 46 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 47 | 48 | class BottomUp { 49 | public: 50 | // O(N*N) & O(1*N) : Where N = given_n 51 | int integerBreak(int given_n) { 52 | vector dp(given_n + 1, -1); 53 | dp[0] = 1; 54 | dp[1] = 1; 55 | dp[2] = 1; 56 | 57 | for(int n = 3; n <= given_n; ++n) { 58 | int maxProduct = 1; 59 | 60 | for(int num = 1; num < n; ++num) { 61 | int nextProduct = max(n - num, dp[n - num]); 62 | maxProduct = max(maxProduct, nextProduct * num); 63 | } 64 | 65 | dp[n] = maxProduct; 66 | } 67 | 68 | return dp[given_n]; 69 | } 70 | }; 71 | 72 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | 74 | Topics: Math | Dynamic Programming 75 | Link : https://leetcode.com/problems/integer-break/description/ 76 | -------------------------------------------------------------------------------- /Dynamic Programming/LIS DP/4 - Print Longest Increasing Subsequence.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the longest increasing subsequence of the given array ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the longest increasing subsequence, using 1D tabulation - O(N*N) & O(N) 8 | vector getLIS(vector& nums) { 9 | int n = nums.size(); 10 | 11 | vector dp(n, 1); // dp[index] represents the length of the LIS ending at that index 12 | vector temp(n, -1); // temp[index] represents the index of the recently seen value which is considered as the part of the LIS ending at that index 13 | 14 | // Find the length of the LIS ending at each index 15 | for(int index = 0; index < n; ++index) { 16 | temp[index] = index; 17 | for(int prevIndex = 0; prevIndex < index; ++prevIndex) { 18 | if(nums[prevIndex] < nums[index] && 1 + dp[prevIndex] > dp[index]) { 19 | dp[index] = max(dp[index], 1 + dp[prevIndex]); 20 | temp[index] = prevIndex; 21 | } 22 | } 23 | } 24 | 25 | int resultIndex = -1; // Stores the index of the value which has to be taken (result value) 26 | int maxLength = -1; // Stores the length of the LIS 27 | 28 | // Find the length of the LIS 29 | for(int index = 0; index < n; ++index) { 30 | if(dp[index] > maxLength) { 31 | maxLength = dp[index]; 32 | resultIndex = index; 33 | } 34 | } 35 | 36 | // Stores the result values 37 | vector LIS; 38 | 39 | // Iterate and store the result values 40 | while(resultIndex != temp[resultIndex]) { 41 | LIS.push_back(nums[resultIndex]); 42 | resultIndex = temp[resultIndex]; 43 | } 44 | LIS.push_back(nums[resultIndex]); 45 | 46 | // Reverse the result array to get the actual order 47 | reverse(begin(LIS), end(LIS)); 48 | 49 | // Return the result array 50 | return LIS; 51 | } 52 | }; 53 | 54 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | Topics: Array | Dynamic Programming 57 | Link : https://www.geeksforgeeks.org/problems/printing-longest-increasing-subsequence/1 58 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/27 - Combination Sum IV/27.1 - Combination Sum IV (Without Sorting).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the number of possible combinations that add up to target. Note that the array values are distinct ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(N^T) & O(T) : Where T = target 7 | int solveWithoutMemo(const vector& nums, int target) { 8 | if(target == 0) 9 | return 1; 10 | 11 | int count = 0; 12 | 13 | for(int num : nums) 14 | if(num <= target) 15 | count += solveWithoutMemo(nums, target - num); 16 | 17 | return count; 18 | } 19 | 20 | // O(N*T) & O(2*T) : Where T = target 21 | int solveWithMemo(vector& dp, const vector& nums, int target) { 22 | if(target == 0) 23 | return 1; 24 | 25 | if(dp[target] != -1) 26 | return dp[target]; 27 | 28 | int count = 0; 29 | 30 | for(int num : nums) 31 | if(num <= target) 32 | count += solveWithMemo(dp, nums, target - num); 33 | 34 | return dp[target] = count; 35 | } 36 | 37 | public: 38 | int numWaysToSumTarget(vector& nums, int target) { 39 | vector dp(target + 1, -1); 40 | return solveWithMemo(dp, nums, target); 41 | } 42 | }; 43 | 44 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 45 | 46 | class BottomUp { 47 | public: 48 | // O(T*N) & O(1*T) : Where T = givenTarget 49 | int numWaysToSumTarget(const vector& nums, int givenTarget) { 50 | vector dp(givenTarget + 1, -1); 51 | dp[0] = 1; 52 | 53 | for(int target = 1; target <= givenTarget; ++target) { 54 | unsigned int count = 0; 55 | 56 | for(int num : nums) { 57 | if(num <= target) { 58 | count += dp[target - num]; 59 | } 60 | } 61 | 62 | dp[target] = count; 63 | } 64 | 65 | return dp[givenTarget]; 66 | } 67 | }; 68 | 69 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 70 | 71 | Topics: Array | Dynamic Programming 72 | Links : https://leetcode.com/problems/combination-sum-iv/ 73 | https://cses.fi/problemset/task/1635/ 74 | -------------------------------------------------------------------------------- /Dynamic Programming/LIS DP/11 - Longest Bitonic Subsequence.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the length of the longest bitonic subsequence. A subsequence of array is called Bitonic if it is first strictly increasing, then strictly decreasing. A strictly increasing or a strictly decreasing sequence should not be considered as a bitonic sequence ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the length of the longest bitonic subsequence, using 1D tabulation - O(N*N) & O(N) 8 | int LongestBitonicSequence(int n, vector& nums) { 9 | vector LIS(n, 1); // LIS[index] represents the length of the LIS ending at that index 10 | vector LDS(n, 1); // LDS[index] represents the length of the LDS ending at that index 11 | 12 | // Compute the length of the LIS of each index 13 | for(int index = 0; index < n; ++index) 14 | for(int prevIndex = 0; prevIndex < index; ++prevIndex) 15 | if(nums[prevIndex] < nums[index]) 16 | LIS[index] = max(LIS[index], 1 + LIS[prevIndex]); 17 | 18 | // Compute the length of the LDS of each index 19 | for(int index = n-1; index >= 0; --index) 20 | for(int nextIndex = n-1; nextIndex > index; --nextIndex) 21 | if(nums[index] > nums[nextIndex]) 22 | LDS[index] = max(LDS[index], 1 + LDS[nextIndex]); 23 | 24 | int maxLenBitonic = 0; 25 | 26 | for(int index = 0; index < n; ++index) { 27 | int lenLIS = LIS[index]; 28 | int lenLDS = LDS[index]; 29 | // If both types of subsequence exists then update the result value by the maximum length 30 | if(lenLIS > 1 && lenLDS > 1) { 31 | maxLenBitonic = max(maxLenBitonic, lenLIS + lenLDS - 1); 32 | } 33 | } 34 | 35 | return maxLenBitonic; 36 | } 37 | }; 38 | 39 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 40 | 41 | Topics: Array | Dynamic Programming 42 | Link : https://www.geeksforgeeks.org/problems/longest-bitonic-subsequence0824/1 43 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/27 - Combination Sum IV/27.2 - Combination Sum IV (With Sorting).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the number of possible combinations that add up to target. Note that the array values are distinct ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N^T) & O(T) : Where T = target 9 | int solveWithoutMemo(const vector& nums, int target) { 10 | if(target == 0) 11 | return 1; 12 | 13 | int count = 0; 14 | 15 | for(int i = 0; (i < n && nums[i] <= target); ++i) 16 | count += solveWithoutMemo(nums, target - nums[i]); 17 | 18 | return count; 19 | } 20 | 21 | // O(N*T) & O(2*T) : Where T = target 22 | int solveWithMemo(vector& dp, const vector& nums, int target) { 23 | if(target == 0) 24 | return 1; 25 | 26 | if(dp[target] != -1) 27 | return dp[target]; 28 | 29 | int count = 0; 30 | 31 | for(int i = 0; (i < n && nums[i] <= target); ++i) 32 | count += solveWithMemo(dp, nums, target - nums[i]); 33 | 34 | return dp[target] = count; 35 | } 36 | 37 | public: 38 | int numWaysToSumTarget(vector& nums, int target) { 39 | n = nums.size(); 40 | sort(begin(nums), end(nums)); 41 | vector dp(target + 1, -1); 42 | return solveWithMemo(dp, nums, target); 43 | } 44 | }; 45 | 46 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 47 | 48 | class BottomUp { 49 | public: 50 | // O(T*N) & O(1*T) : Where T = givenTarget 51 | int numWaysToSumTarget(vector& nums, int givenTarget) { 52 | int n = nums.size(); 53 | sort(begin(nums), end(nums)); 54 | 55 | vector dp(givenTarget + 1, -1); 56 | dp[0] = 1; 57 | 58 | for(int target = 1; target <= givenTarget; ++target) { 59 | unsigned int count = 0; 60 | 61 | for(int i = 0; (i < n && nums[i] <= target); ++i) { 62 | count += dp[target - nums[i]]; 63 | } 64 | 65 | dp[target] = count; 66 | } 67 | 68 | return dp[givenTarget]; 69 | } 70 | }; 71 | 72 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | 74 | Topics: Array | Dynamic Programming 75 | Links : https://leetcode.com/problems/combination-sum-iv/ 76 | https://cses.fi/problemset/task/1635/ 77 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/28 - Removing Digits/Removing Digits.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum steps required to make the given number equal to 0. On each step, you may subtract one of the digits from the number ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(LogN^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n == 0) 9 | return 0; 10 | 11 | int minSteps = INT_MAX; 12 | int num = n; 13 | 14 | while(num) { 15 | int digit = num % 10; 16 | num /= 10; 17 | if(digit == 0) continue; 18 | int nextSteps = solveWithoutMemo(n - digit); 19 | minSteps = min(minSteps, nextSteps + 1); 20 | } 21 | 22 | return minSteps; 23 | } 24 | 25 | // O(LogN*N) & O(2*N) 26 | int solveWithMemo(vector& dp, int n) { 27 | if(n == 0) 28 | return 0; 29 | 30 | if(dp[n] != -1) 31 | return dp[n]; 32 | 33 | int minSteps = INT_MAX; 34 | int num = n; 35 | 36 | while(num) { 37 | int digit = num % 10; 38 | num /= 10; 39 | if(digit == 0) continue; 40 | int nextSteps = solveWithMemo(dp, n - digit); 41 | minSteps = min(minSteps, nextSteps + 1); 42 | } 43 | 44 | return dp[n] = minSteps; 45 | } 46 | 47 | public: 48 | int minStepsToMakeZero(int n) { 49 | vector dp(n + 1, -1); 50 | return solveWithMemo(dp, n); 51 | } 52 | }; 53 | 54 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | class BottomUp { 57 | public: 58 | // O(NLogN) & O(1*N) : Where N = given_n 59 | int minStepsToMakeZero(int given_n) { 60 | vector dp(given_n + 1, -1); 61 | dp[0] = 0; 62 | 63 | for(int n = 1; n <= given_n; ++n) { 64 | int minSteps = INT_MAX; 65 | int num = n; 66 | 67 | while(num) { 68 | int digit = num % 10; 69 | num /= 10; 70 | if(digit == 0) continue; 71 | int nextSteps = dp[n - digit]; 72 | minSteps = min(minSteps, nextSteps + 1); 73 | } 74 | 75 | dp[n] = minSteps; 76 | } 77 | 78 | return dp[given_n]; 79 | } 80 | }; 81 | 82 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 83 | 84 | Topics: Math | Dynamic Programming 85 | Link : https://cses.fi/problemset/task/1637 86 | -------------------------------------------------------------------------------- /Dynamic Programming/String DP/9 - Print Longest Common Substring.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the longest common substring of given two strings ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // #1 Method to find the longest common substring, using 2D tabulation - O(N*M) & O(N*M) 8 | string getLongestCommonSubstr_V1(string& s1, string& s2) { 9 | int n = s1.size(), m = s2.size(), maxLength = 0, endIndex = 0; 10 | 11 | // 2D DP table 12 | vector> dp(n + 1, vector(m + 1, 0)); 13 | 14 | for(int i = 1; i <= n; ++i) { 15 | for(int j = 1; j <= m; ++j) { 16 | // If both the letters match 17 | if(s1[i - 1] == s2[j - 1]) { 18 | dp[i][j] = 1 + dp[i - 1][j - 1]; 19 | if(dp[i][j] > maxLength) { 20 | maxLength = dp[i][j]; 21 | endIndex = i; 22 | } 23 | } 24 | // Else when both the letters don't match 25 | else { 26 | dp[i][j] = 0; 27 | } 28 | } 29 | } 30 | 31 | // Return the result string 32 | return s1.substr(endIndex - maxLength, maxLength); 33 | } 34 | 35 | // #2 Method to find the longest common substring, using 1D tabulation - O(N*M) & O(M) 36 | string getLongestCommonSubstr_V2(string& s1, string& s2) { 37 | int n = s1.size(), m = s2.size(), maxLength = 0, endIndex = 0; 38 | 39 | // 1D DP tables 40 | vector prevRow(m + 1, 0), currRow(m + 1, 0); 41 | 42 | for(int i = 1; i <= n; ++i) { 43 | for(int j = 1; j <= m; ++j) { 44 | // If both the letters match 45 | if(s1[i - 1] == s2[j - 1]) { 46 | currRow[j] = 1 + prevRow[j - 1]; 47 | if(currRow[j] > maxLength) { 48 | maxLength = currRow[j]; 49 | endIndex = i; 50 | } 51 | } 52 | // Else when both the letters don't match 53 | else { 54 | currRow[j] = 0; 55 | } 56 | } 57 | prevRow = currRow; 58 | } 59 | 60 | // Return the result string 61 | return s1.substr(endIndex - maxLength, maxLength); 62 | } 63 | }; 64 | 65 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 66 | 67 | Topics: String | Dynamic Programming 68 | Link : https://www.geeksforgeeks.org/print-longest-common-substring/ 69 | -------------------------------------------------------------------------------- /Stack/Reverse Substrings Between Each Pair of Parentheses.cpp: -------------------------------------------------------------------------------- 1 | // Code to reverse the strings in each pair of matching parentheses, starting from the innermost one. So that the result should not contain any brackets ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------- 4 | 5 | class Solution { 6 | public: 7 | // Method to reverse the string in specified way using 1 stack - O(N*N) & O(N) 8 | string reverseParentheses(const string& s) { 9 | int n = s.size(), countTotalParentheses = 0; 10 | 11 | vector countLeft(n), countRight(n); 12 | 13 | // Iterate and count the total number of parentheses present at the left side of each index 14 | for(int i = 0; i < n; ++i) { 15 | if(s[i] == ')' || s[i] == '(') countTotalParentheses++; 16 | countLeft[i] = countTotalParentheses; 17 | } 18 | 19 | countTotalParentheses = 0; 20 | 21 | // Iterate and count the total number of parentheses present at the right side of each index 22 | for(int i = n-1; i >= 0; --i) { 23 | if(s[i] == ')' || s[i] == '(') countTotalParentheses++; 24 | countRight[i] = countTotalParentheses; 25 | } 26 | 27 | stack> stack; 28 | string output; 29 | 30 | for(int j = 0; j < n; ++j) { 31 | // If the jth letter is a closing parentheses then reverse the valid part of the string 32 | if(s[j] == ')') { 33 | auto [p, i] = stack.top(); stack.pop(); 34 | int substringLength = j-i-1; 35 | int countValidLetters = countTotalParentheses - countLeft[i] - countRight[j]; 36 | int lettersToReverse = substringLength - countValidLetters; 37 | int size = output.size(); 38 | reverseString(output, size-lettersToReverse, size-1); 39 | } 40 | // Else if the jth letter is a opening parentheses then store it with it's index to the stack 41 | else if(s[j] == '(') { 42 | stack.push({s[j], j}); 43 | } 44 | // Else it's a lowercase english letter hence store it to the output string 45 | else { 46 | output.push_back(s[j]); 47 | } 48 | } 49 | 50 | return output; 51 | } 52 | 53 | private: 54 | // Method to reverse a string - O(N) & O(1) 55 | void reverseString(string& str, int start, int end) { 56 | while(start < end) { 57 | swap(str[start], str[end]); 58 | start++; 59 | end--; 60 | } 61 | } 62 | }; 63 | 64 | --------------------------------------------------------------------------------------------------------------- 65 | 66 | /* 67 | Topics: String | Stack 68 | Link : https://leetcode.com/problems/reverse-substrings-between-each-pair-of-parentheses/description/ 69 | */ 70 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/6 - Climbing Stairs/Climbing Stairs.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the total number of distinct ways from which you can climb to the top ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(2^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n <= 1) 9 | return 1; // Here, We have 1 way to reach point 0 from point n 10 | 11 | int jump1StepDown = solveWithoutMemo(n - 1); 12 | int jump2StepDown = solveWithoutMemo(n - 2); 13 | 14 | return jump1StepDown + jump2StepDown; 15 | } 16 | 17 | // O(2*N) & O(2*N) 18 | int solveWithMemo(vector& memory, int n) { 19 | if(n <= 1) 20 | return 1; // Here, We have 1 way to reach point 0 from point n 21 | 22 | if(memory[n] != -1) 23 | return memory[n]; 24 | 25 | int jump1StepDown = solveWithMemo(memory, n - 1); 26 | int jump2StepDown = solveWithMemo(memory, n - 2); 27 | 28 | return memory[n] = jump1StepDown + jump2StepDown; 29 | } 30 | 31 | public: 32 | // Method to count ways to reach nth step, using recursion with memoization - O(N) & O(N) 33 | int numWaysToReachTop(int n) { 34 | vector memory(n + 1, -1); 35 | return solveWithMemo(memory, n); 36 | } 37 | }; 38 | 39 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 40 | 41 | class BottomUp { 42 | // O(1*N) & O(1*N) 43 | int solveWith1DTable(int n) { 44 | vector dp(n + 1, -1); 45 | dp[0] = 1; 46 | dp[1] = 1; 47 | 48 | for(int i = 2; i <= n; ++i) { 49 | int jump1StepDown = dp[i - 1]; 50 | int jump2StepDown = dp[i - 2]; 51 | dp[i] = jump1StepDown + jump2StepDown; 52 | } 53 | 54 | return dp[n]; 55 | } 56 | 57 | // O(1*N) & O(1) 58 | int solveWithoutTable(int n) { 59 | int dp_i_2 = 1; 60 | int dp_i_1 = 1; 61 | int dp_i = 1; // For when n = 1, because loop won't work for it 62 | 63 | for(int i = 2; i <= n; ++i) { 64 | int jump1StepDown = dp_i_1; 65 | int jump2StepDown = dp_i_2; 66 | dp_i = jump1StepDown + jump2StepDown; 67 | dp_i_2 = dp_i_1; 68 | dp_i_1 = dp_i; 69 | } 70 | 71 | return dp_i; 72 | } 73 | 74 | public: 75 | int numWaysToReachTop(int n) { 76 | return solveWithoutTable(n); 77 | } 78 | }; 79 | 80 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 81 | 82 | Topics: Math | Dynamic Programming | Memoization 83 | Link : https://leetcode.com/problems/climbing-stairs/description/ 84 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/10 - Solving Questions With Brainpower/Solving Questions With Brainpower.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the maximum points you can earn for the exam ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | typedef long long LL; 7 | int n; 8 | 9 | // O(2^N) & O(N) 10 | LL solveWithoutMemo(vector>& questions, int i) { 11 | if(i >= n) 12 | return 0; 13 | 14 | LL solveQuestion = questions[i][0] + solveWithoutMemo(questions, i + questions[i][1] + 1); 15 | LL skipQuestion = solveWithoutMemo(questions, i + 1); 16 | 17 | return max(solveQuestion, skipQuestion); 18 | } 19 | 20 | // O(2*N) & O(2*N) 21 | LL solveWithMemo(vector& dp, vector>& questions, int i) { 22 | if(i >= n) 23 | return 0; 24 | 25 | if(dp[i] != -1) 26 | return dp[i]; 27 | 28 | LL solveQuestion = questions[i][0] + solveWithMemo(dp, questions, i + questions[i][1] + 1); 29 | LL skipQuestion = solveWithMemo(dp, questions, i + 1); 30 | 31 | return dp[i] = max(solveQuestion, skipQuestion); 32 | } 33 | 34 | public: 35 | LL mostPoints(vector>& questions) { 36 | n = questions.size(); 37 | vector dp(n, -1); 38 | return solveWithMemo(dp, questions, 0); 39 | } 40 | }; 41 | 42 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 43 | 44 | class BottomUp { 45 | using LL = long long; 46 | 47 | public: 48 | // O(1*N) & O(1*N) 49 | LL mostPoints(vector>& questions) { 50 | int n = questions.size(); 51 | 52 | vector dp(n + 1, -1); 53 | dp[n] = 0; 54 | 55 | for(int i = n-1; i >= 0; --i) { 56 | LL nextQuestion = i + questions[i][1] + 1; 57 | LL solveQuestion = questions[i][0] + (nextQuestion <= n ? dp[nextQuestion] : 0); 58 | LL skipQuestion = dp[i + 1]; 59 | dp[i] = max(solveQuestion, skipQuestion); 60 | } 61 | 62 | return dp[0]; 63 | } 64 | // Note: We can't do space optimization in this, as you could see dp[nextQuestion], the value of `nextQuestion` could be anything, overall its not constant 65 | }; 66 | 67 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 68 | 69 | Topics: Array | Dynamic Programming 70 | Link : https://leetcode.com/problems/solving-questions-with-brainpower/description/ 71 | -------------------------------------------------------------------------------- /Dynamic Programming/Graph DP/3 - Cheapest Flights Within K Stops.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the cheapest price from source to destination with at most k stops. If there is no such route then return -1 ~ coded by Hiren 2 | 3 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class DynamicProgramming { 6 | vector>> adjList; 7 | 8 | // O(N^K) & O(K) : Where N = total flights or total nodes. 9 | int solveWithoutMemo(int src, int dst, int k) { 10 | if(src == dst) 11 | return (k >= 0) ? 0 : INT_MAX; // If reached destination within k stops then return 0 as an indication 12 | 13 | if(k == 0) 14 | return INT_MAX; 15 | 16 | int minPrice = INT_MAX; 17 | 18 | for(auto& [neighbor, edgeWeight] : adjList[src]) { 19 | int nextPrice = solveWithoutMemo(neighbor, dst, k - 1); 20 | if(nextPrice != INT_MAX) { 21 | minPrice = min(minPrice, nextPrice + edgeWeight); 22 | } 23 | } 24 | 25 | return minPrice; 26 | } 27 | 28 | // O(N*K) & O(N*K) : Where N = total flights or total nodes. 29 | int solveWithMemo(vector>& dp, int src, int dst, int k) { 30 | if(src == dst) 31 | return (k >= 0) ? 0 : INT_MAX; // If reached destination within k stops then return 0 as an indication 32 | 33 | if(k == 0) 34 | return INT_MAX; 35 | 36 | if(dp[src][k] != -1) 37 | return dp[src][k]; 38 | 39 | int minPrice = INT_MAX; 40 | 41 | for(auto& [neighbor, edgeWeight] : adjList[src]) { 42 | int nextPrice = solveWithMemo(dp, neighbor, dst, k - 1); 43 | if(nextPrice != INT_MAX) { 44 | minPrice = min(minPrice, nextPrice + edgeWeight); 45 | } 46 | } 47 | 48 | return dp[src][k] = minPrice; 49 | } 50 | 51 | public: 52 | int findCheapestPrice(int n, vector>& flights, int src, int dst, int k) { 53 | adjList.resize(n); 54 | 55 | for(auto& f : flights) { // Construct the graph 56 | int from = f[0]; 57 | int to = f[1]; 58 | int price = f[2]; 59 | adjList[from].push_back({to, price}); 60 | } 61 | 62 | vector> dp(n, vector(k + 2, -1)); 63 | int minPrice = solveWithMemo(dp, src, dst, k + 1); 64 | 65 | return (minPrice == INT_MAX) ? -1 : minPrice; 66 | } 67 | }; 68 | 69 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 70 | 71 | Topics: Dynamic Programming | Depth-First Search | Graph 72 | Link : https://leetcode.com/problems/cheapest-flights-within-k-stops/description/ 73 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/12 - Minimum Steps To Minimize N As Per Given Condition/12.1 - Minimum Steps To Minimize N As Per Given Condition.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum steps required to minimize n to 1 according to the following criteria: If n is divisible by 2 then you may reduce n to n/2. If n is divisible by 3 then you may reduce n to n/3. Otherwise, Decrement n by 1 ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 4 | 5 | class TopDown { 6 | // O(3^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n == 1) 9 | return 0; 10 | 11 | int minSteps = solveWithoutMemo(n - 1); 12 | 13 | if(n % 2 == 0) minSteps = min(minSteps, solveWithoutMemo(n / 2)); 14 | if(n % 3 == 0) minSteps = min(minSteps, solveWithoutMemo(n / 3)); 15 | 16 | return minSteps + 1; 17 | } 18 | 19 | // O(3*N) & O(2*N) 20 | int solveWithMemo(vector& dp, int n) { 21 | if(n == 1) 22 | return 0; 23 | 24 | if(dp[n] != -1) 25 | return dp[n]; 26 | 27 | int minSteps = solveWithMemo(dp, n - 1); 28 | 29 | if(n % 2 == 0) minSteps = min(minSteps, solveWithMemo(dp, n / 2)); 30 | if(n % 3 == 0) minSteps = min(minSteps, solveWithMemo(dp, n / 3)); 31 | 32 | return dp[n] = minSteps + 1; 33 | } 34 | 35 | public: 36 | int minStepsToMakeOne(int n) { 37 | vector dp(n + 1, -1); 38 | return solveWithMemo(dp, n); 39 | } 40 | }; 41 | 42 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 43 | 44 | class BottomUp { 45 | public: 46 | // O(1*N) & O(1*N) : Where N = given_n 47 | int minStepsToMakeOne(int given_n) { 48 | vector dp(given_n + 1, -1); 49 | dp[1] = 0; 50 | 51 | for(int n = 2; n <= given_n; ++n) { 52 | int minSteps = dp[n - 1]; 53 | if(n % 2 == 0) minSteps = minSteps = min(minSteps, dp[n / 2]); 54 | if(n % 3 == 0) minSteps = minSteps = min(minSteps, dp[n / 3]); 55 | dp[n] = minSteps + 1; 56 | } 57 | 58 | return dp[given_n]; 59 | } 60 | }; 61 | 62 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 63 | 64 | Topics: Array | Dynamic Programming 65 | Links : https://leetcode.com/discuss/interview-question/538568/google-onsite-min-operations-to-reduce-number-to-1 66 | https://www.geeksforgeeks.org/problems/minimum-steps-to-minimize-n-as-per-given-condition0618/0 67 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/11 - Count Ways To Build Good Strings/Count Ways To Build Good Strings.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the number of good strings the can be constructed satisfying the mentioned properties ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 4 | 5 | class TopDown { 6 | const int MOD = 1e9+7; 7 | int low, high, zero, one; 8 | 9 | // O(2^strLen) & O(high) 10 | int solveWithoutMemo(int strLen) { 11 | if(strLen > high) 12 | return 0; 13 | 14 | int appendZero = solveWithoutMemo(strLen + zero); 15 | int appendOne = solveWithoutMemo(strLen + one); 16 | 17 | return (strLen >= low) + (appendZero + appendOne) % MOD; 18 | } 19 | 20 | // O(2*high) & O(2*high) 21 | int solveWithMemo(vector& dp, int strLen) { 22 | if(strLen > high) 23 | return 0; 24 | 25 | if(dp[strLen] != -1) 26 | return dp[strLen]; 27 | 28 | int appendZero = solveWithMemo(dp, strLen + zero); 29 | int appendOne = solveWithMemo(dp, strLen + one); 30 | 31 | return dp[strLen] = (strLen >= low) + (appendZero + appendOne) % MOD; 32 | } 33 | 34 | public: 35 | int countGoodStrings(int l, int h, int z, int o) { 36 | low = l, high = h, zero = z, one = o; 37 | vector dp(high + 1, -1); 38 | return solveWithMemo(dp, 0); 39 | } 40 | }; 41 | 42 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 43 | 44 | class BottomUp { 45 | const int MOD = 1e9+7; 46 | 47 | public: 48 | // O(1*high) & O(1*high) 49 | int countGoodStrings(int low, int high, int zero, int one) { 50 | vector dp(high + 1, -1); 51 | 52 | for(int strLen = high; strLen >= 0; --strLen) { 53 | int nextIndex1 = strLen + zero; 54 | int nextIndex2 = strLen + one; 55 | int appendZero = (nextIndex1 <= high) ? dp[nextIndex1] : 0; 56 | int appendOne = (nextIndex2 <= high) ? dp[nextIndex2] : 0; 57 | dp[strLen] = (strLen >= low) + (appendZero + appendOne) % MOD; 58 | } 59 | 60 | return dp[0]; 61 | } 62 | // Note: We can't do space optimization in this, as you could see dp[nextIndex1], dp[nextIndex2], the value of `nextIndex1`, `nextIndex2` could be anything, overall its not constant 63 | }; 64 | 65 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 66 | 67 | Topics: Dynamic Programming 68 | Link : https://leetcode.com/problems/count-ways-to-build-good-strings/description/?envType=daily-question&envId=2024-12-30 69 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/4 - Tribonacci Number/Tribonacci Number.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the nth number of the tribonacci sequence ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(3^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n < 3) 9 | return (n == 0) ? 0 : 1; 10 | 11 | int prevNum1 = solveWithoutMemo(n - 1); 12 | int prevNum2 = solveWithoutMemo(n - 2); 13 | int prevNum3 = solveWithoutMemo(n - 3); 14 | 15 | return prevNum1 + prevNum2 + prevNum3; 16 | } 17 | 18 | // O(3*N) & O(2*N) 19 | int solveWithMemo(vector& memory, int n) { 20 | if(n < 3) 21 | return (n == 0) ? 0 : 1; 22 | 23 | if(memory[n] != -1) 24 | return memory[n]; 25 | 26 | int prevNum1 = solveWithMemo(memory, n - 1); 27 | int prevNum2 = solveWithMemo(memory, n - 2); 28 | int prevNum3 = solveWithMemo(memory, n - 3); 29 | 30 | return memory[n] = (prevNum1 + prevNum2 + prevNum3); 31 | } 32 | 33 | public: 34 | // Method to find nth tribonacci number, using recursion with memoization - O(N) & O(N) 35 | int nthTribonacci(int n) { 36 | vector memory(n + 1, -1); 37 | return solveWithMemo(memory, n); 38 | } 39 | }; 40 | 41 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 42 | 43 | class BottomUp { 44 | // O(4*N) & O(1*N) 45 | int solveWith1DTable(int n) { 46 | vector dp(n + 1, -1); 47 | dp[0] = 0; 48 | dp[1] = 1; 49 | dp[2] = 1; 50 | 51 | for(int i = 3; i <= n; ++i) { 52 | int prevNum1 = dp[i - 1]; 53 | int prevNum2 = dp[i - 2]; 54 | int prevNum3 = dp[i - 3]; 55 | dp[i] = (prevNum1 + prevNum2 + prevNum3); 56 | } 57 | 58 | return dp[n]; 59 | } 60 | 61 | // O(4*N) & O(1) 62 | int solveWithoutTable(int n) { 63 | int dp_i_3 = 0; 64 | int dp_i_2 = 1; 65 | int dp_i_1 = 1; 66 | int dp_i = 1; 67 | 68 | for(int i = 3; i <= n; ++i) { 69 | int prevNum1 = dp_i_1; 70 | int prevNum2 = dp_i_2; 71 | int prevNum3 = dp_i_3; 72 | dp_i = (prevNum1 + prevNum2 + prevNum3); 73 | dp_i_3 = dp_i_2; 74 | dp_i_2 = dp_i_1; 75 | dp_i_1 = dp_i; 76 | } 77 | 78 | return dp_i; 79 | } 80 | 81 | public: 82 | int nthTribonacci(int n) { 83 | if(n < 3) 84 | return (n == 0) ? 0 : 1; 85 | return solveWithoutTable(n); 86 | } 87 | }; 88 | 89 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 90 | 91 | Topics: Dynamic Programming | Math | Memoization 92 | Link : https://leetcode.com/problems/N-th-tribonacci-number/description/ 93 | -------------------------------------------------------------------------------- /Dynamic Programming/String DP/15 - Shortest Common Supersequence.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the shortest string that has both str1 and str2 as subsequences. If there are multiple valid strings, return any of them ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | public: 7 | // Method to find the shortest common supersequence, using 2D tabulation - O(N*M) & O(N*M) 8 | string shortestCommonSupersequence(string& s1, string& s2) { 9 | int n = s1.size(), m = s2.size(); 10 | 11 | // 2D DP table 12 | vector> dp(n + 1, vector(m + 1, 0)); 13 | 14 | // Find the length of the longest common subsequence of both the strings 15 | for(int i = 1; i <= n; ++i) { 16 | for(int j = 1; j <= m; ++j) { 17 | if(s1[i - 1] == s2[j - 1]) { 18 | dp[i][j] = 1 + dp[i - 1][j - 1]; 19 | } 20 | else { 21 | dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); 22 | } 23 | } 24 | } 25 | 26 | string answer; 27 | 28 | int i = n, j = m; 29 | 30 | while(i > 0 && j > 0) { 31 | // If both the letters match 32 | if(s1[i - 1] == s2[j - 1]) { 33 | // Take only 1 letter 34 | answer.push_back(s1[i - 1]); 35 | i--; 36 | j--; 37 | } 38 | // Else when both the letters don't match 39 | else { 40 | // If it's maximum then string1 will shrink by size 1. So before shrink take that dropped letter of string1 41 | if(dp[i - 1][j] > dp[i][j - 1]) { 42 | answer.push_back(s1[i - 1]); 43 | i--; 44 | } 45 | // Else if it's maximum then string2 will shrink by size 1. So before shrink take that dropped letter of string2 46 | else { 47 | answer.push_back(s2[j - 1]); 48 | j--; 49 | } 50 | } 51 | } 52 | 53 | // Store the remaining letters of string1 to the answer 54 | while(i > 0) { 55 | answer.push_back(s1[i - 1]); 56 | i--; 57 | } 58 | 59 | // Store the remaining letters of string2 to the answer 60 | while(j > 0) { 61 | answer.push_back(s2[j - 1]); 62 | j--; 63 | } 64 | 65 | // Reverse the answer array to get the actual order 66 | reverse(begin(answer), end(answer)); 67 | 68 | return answer; 69 | } 70 | }; 71 | 72 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | 74 | Topics: String | Dynamic Programming 75 | Links : https://leetcode.com/problems/shortest-common-supersequence/ 76 | https://github.com/hiren-j/dsaAffection/blob/C%2B%2B/Dynamic%20Programming/String%20DP/Longest%20Common%20Subsequence.cpp 77 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/20 - Jump Game/Jump Game.cpp: -------------------------------------------------------------------------------- 1 | // Code to check whether you can reach the last index of the array or not. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position ~ coded by Hiren 2 | 3 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(M^N) & O(N) : Where M = maximum element of array 9 | bool solveWithoutMemo(vector& nums, int index) { 10 | if(index == n-1) 11 | return true; 12 | 13 | for(int jump = 1; (jump <= nums[index] && index + jump < n); ++jump) 14 | if(solveWithoutMemo(nums, index + jump)) 15 | return true; // Return true if you reach last index from any of the possibility 16 | 17 | return false; 18 | } 19 | 20 | // O(M*N) & O(2*N) : Where M = maximum element of array 21 | bool solveWithMemo(vector& dp, vector& nums, int index) { 22 | if(index == n-1) 23 | return true; 24 | 25 | if(dp[index] != -1) 26 | return dp[index]; 27 | 28 | for(int jump = 1; (jump <= nums[index] && index + jump < n); ++jump) 29 | if(solveWithMemo(dp, nums, index + jump)) 30 | return dp[index] = true; // Return true if you reach last index from any of the possibility 31 | 32 | return dp[index] = false; 33 | } 34 | 35 | public: 36 | bool canReachLastIndex(vector& nums) { 37 | n = nums.size(); 38 | vector dp(n-1, -1); 39 | return solveWithMemo(dp, nums, 0); 40 | } 41 | }; 42 | 43 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 44 | 45 | class BottomUp { 46 | public: 47 | // O(N*M) & O(1*N) : Where M = maximum element of array 48 | bool canReachLastIndex(vector& nums) { 49 | int n = nums.size(); 50 | 51 | vector dp(n, false); 52 | dp[n - 1] = true; 53 | 54 | for(int index = n-2; index >= 0; --index) { 55 | // dp[index] = false; // If you want dp array like this: vector dp(n, -1); Then uncomment this line 56 | 57 | for(int jump = 1; (jump <= nums[index] && index + jump < n); ++jump) { 58 | if(dp[index + jump]) { 59 | dp[index] = true; 60 | break; 61 | } 62 | } 63 | } 64 | 65 | return dp[0]; 66 | } 67 | }; 68 | 69 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 70 | 71 | Topics: Array | Dynamic Programming | Greedy 72 | Link : https://leetcode.com/problems/jump-game/ 73 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/21 - Jump Game II/Jump Game II.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum number of jumps to reach the last index of the array ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(M^N) & O(N) : Where M = maximum element of array 9 | int solveWithoutMemo(vector& nums, int index) { 10 | if(index == n-1) 11 | return 0; 12 | 13 | int minJumps = INT_MAX; 14 | 15 | for(int jump = 1; (jump <= nums[index] && index + jump < n); ++jump) { 16 | int nextJumps = solveWithoutMemo(nums, index + jump); 17 | 18 | if(nextJumps != INT_MAX) { 19 | minJumps = min(minJumps, nextJumps + 1); // Update result if you reached the last index 20 | } 21 | } 22 | 23 | return minJumps; 24 | } 25 | 26 | // O(M*N) & O(2*N) : Where M = maximum element of array 27 | int solveWithMemo(vector& dp, vector& nums, int index) { 28 | if(index == n-1) 29 | return 0; 30 | 31 | if(dp[index] != -1) 32 | return dp[index]; 33 | 34 | int minJumps = INT_MAX; 35 | 36 | for(int jump = 1; (jump <= nums[index] && index + jump < n); ++jump) { 37 | int nextJumps = solveWithMemo(dp, nums, index + jump); 38 | 39 | if(nextJumps != INT_MAX) { 40 | minJumps = min(minJumps, nextJumps + 1); // Update result if you reached the last index 41 | } 42 | } 43 | 44 | return dp[index] = minJumps; 45 | } 46 | 47 | public: 48 | int minJumpsToLastIndex(vector& nums) { 49 | n = nums.size(); 50 | vector dp(n-1, -1); 51 | return solveWithMemo(dp, nums, 0); 52 | } 53 | }; 54 | 55 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 56 | 57 | class BottomUp { 58 | public: 59 | // O(N*M) & O(1*N) : Where M = maximum element of array 60 | int minJumpsToLastIndex(vector& nums) { 61 | int n = nums.size(); 62 | 63 | vector dp(n, -1); 64 | dp[n - 1] = 0; 65 | 66 | for(int index = n-2; index >= 0; --index) { 67 | int minJumps = INT_MAX; 68 | 69 | for(int jump = 1; (jump <= nums[index] && index + jump < n); ++jump) { 70 | int nextJumps = dp[index + jump]; 71 | 72 | if(nextJumps != INT_MAX) { 73 | minJumps = min(minJumps, nextJumps + 1); 74 | } 75 | } 76 | 77 | dp[index] = minJumps; 78 | } 79 | 80 | return dp[0]; 81 | } 82 | }; 83 | 84 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- 85 | 86 | Topics: Array | Dynamic Programming | Greedy 87 | Link : https://leetcode.com/problems/jump-game-ii/description/ 88 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/38 - Number of Increasing Paths In Grid.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Code to find the number of strictly increasing paths in the grid such that you can start from any cell and end at any cell ~ coded by Hiren 3 | 4 | ------------------------------------------------------------------------------------------------------------------------------------------------------- 5 | 6 | /* 7 | DON'T IGNORE MUST READ: For the bottom-up solution of this problem, I created it and run it but it didn't passed all the testcases. 8 | So I would say there are only 3 problems in the whole series which doesn't contain the bottom-up solution 9 | due to this reason. These 3 problems lies in this folder (Multi-Dimensional DP Folder). 10 | */ 11 | 12 | ------------------------------------------------------------------------------------------------------------------------------------------------------- 13 | 14 | class TopDown { 15 | const vector> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 16 | const int MOD = 1e9 + 7; 17 | int M, N; 18 | 19 | bool isValid(int R, int C) { 20 | return R >= 0 && C >= 0 && R < M && C < N; 21 | } 22 | 23 | // O(M*N * 4^(M*N)) & O(M*N) 24 | int solveWithoutMemo(const vector>& grid, int R, int C) { 25 | int count = 1; 26 | 27 | for(const auto& D : dirs) { 28 | int newR = R + D[0]; 29 | int newC = C + D[1]; 30 | if(isValid(newR, newC) && grid[newR][newC] > grid[R][C]) { 31 | count = (count + solveWithoutMemo(grid, newR, newC)) % MOD; 32 | } 33 | } 34 | 35 | return count; 36 | } 37 | 38 | // O(M*N + 4*M*N) & O(2*M*N) 39 | int solveWithMemo(vector>& dp, const vector>& grid, int R, int C) { 40 | if(dp[R][C] != -1) 41 | return dp[R][C]; 42 | 43 | int count = 1; 44 | 45 | for(const auto& D : dirs) { 46 | int newR = R + D[0]; 47 | int newC = C + D[1]; 48 | if(isValid(newR, newC) && grid[newR][newC] > grid[R][C]) { 49 | count = (count + solveWithMemo(dp, grid, newR, newC)) % MOD; 50 | } 51 | } 52 | 53 | return dp[R][C] = count; 54 | } 55 | 56 | public: 57 | // Method to find number of strictly increasing paths, using recursion with memoization - O(M*N) & O(M*N) 58 | int countPaths(vector>& grid) { 59 | M = grid.size(), N = grid[0].size(); 60 | int count = 0; 61 | 62 | vector> dp(M, vector(N, -1)); 63 | 64 | for(int R = 0; R < M; ++R) 65 | for(int C = 0; C < N; ++C) 66 | count = (count + solveWithMemo(dp, grid, R, C)) % MOD; 67 | 68 | return count; 69 | } 70 | }; 71 | 72 | ------------------------------------------------------------------------------------------------------------------------------------------------------- 73 | 74 | Topics: Array | Dynamic Programming | Depth-First Search | Breadth-First Search | Graph | Topological Sort | Memoization | Matrix | Weekly Contest 300 75 | Link : https://leetcode.com/problems/number-of-increasing-paths-in-a-grid/description/ 76 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/17 - Climbing Stairs II/17.2 - Climbing Stairs II (Loop Version).cpp: -------------------------------------------------------------------------------- 1 | // Code to find minimum cost to reach step n ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(3^N) & O(N) 9 | int solveWithoutMemo(const vector& costs, int i) { 10 | if(i == n) 11 | return 0; 12 | 13 | int minCost = INT_MAX; 14 | 15 | for(int jump = 1; (jump <= 3 && i + jump <= n); ++jump) { 16 | int j = i + jump; 17 | int jumpCost = costs[j - 1] + pow(j - i, 2); 18 | int nextCost = solveWithoutMemo(costs, j); 19 | minCost = min(minCost, jumpCost + nextCost); 20 | } 21 | 22 | return minCost; 23 | } 24 | 25 | // O(3*N) & O(2*N) 26 | int solveWithMemo(vector& dp, const vector& costs, int i) { 27 | if(i == n) 28 | return 0; 29 | 30 | if(dp[i] != -1) 31 | return dp[i]; 32 | 33 | int minCost = INT_MAX; 34 | 35 | for(int jump = 1; (jump <= 3 && i + jump <= n); ++jump) { 36 | int j = i + jump; 37 | int jumpCost = costs[j - 1] + pow(j - i, 2); 38 | int nextCost = solveWithMemo(dp, costs, j); 39 | minCost = min(minCost, jumpCost + nextCost); 40 | } 41 | 42 | return dp[i] = minCost; 43 | } 44 | 45 | public: 46 | // Method to find minimum cost to reach step n, using recursion with memoization - O(N) & O(N) 47 | int climbStairsII(int step_n, vector& costs) { 48 | n = step_n; 49 | vector dp(n, -1); 50 | return solveWithMemo(dp, costs, 0); 51 | } 52 | }; 53 | 54 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | class BottomUp { 57 | public: 58 | // O(N) & O(N) 59 | int climbStairsII(int n, const vector& costs) { 60 | vector dp(n + 1, -1); 61 | dp[n] = 0; 62 | 63 | for(int i = n-1; i >= 0; --i) { 64 | int minCost = INT_MAX; 65 | 66 | for(int jump = 1; (jump <= 3 && i + jump <= n); ++jump) { 67 | int j = i + jump; 68 | int jumpCost = costs[j - 1] + pow(j - i, 2); 69 | int nextCost = dp[j]; 70 | minCost = min(minCost, jumpCost + nextCost); 71 | } 72 | 73 | dp[i] = minCost; 74 | } 75 | 76 | return dp[0]; 77 | } 78 | }; 79 | // Note: We can optimize this without using 1D dp array. I am not doing here because it will look inconsistent with this loop version. So you can use `solveWithoutTable()` of 17.1 for this 17.2 80 | 81 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 82 | 83 | Topics: Array | Dynamic Programming | Biweekly Contest 166 84 | Link : https://leetcode.com/problems/climbing-stairs-ii/description/ 85 | -------------------------------------------------------------------------------- /Backtracking/Subset Sums.cpp: -------------------------------------------------------------------------------- 1 | // Program to find the sums of all the subsets ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // #1 Backtracking approach: 8 | class Backtracking_V1 { 9 | vector sums; 10 | 11 | void getAllSubestsSum(vector& nums, int N, int currSum, int J) { 12 | // Edge case: If all the array elements are taken 13 | if(J >= N) { 14 | sums.push_back(currSum); 15 | return; // Backtrack 16 | } 17 | 18 | getAllSubestsSum(nums, N, currSum+nums[J], J+1); // Include the element and move on 19 | getAllSubestsSum(nums, N, currSum, J+1); // Exclude the element and move on 20 | } 21 | 22 | public: 23 | // Method to find the sums of all the subsets - O(2^N) & O(2^N) 24 | vector subsetSums(vector& nums, int N) { 25 | getAllSubestsSum(nums, N, 0, 0); 26 | return sums; 27 | } 28 | }; 29 | 30 | // #2 Backtracking approach: 31 | class Backtracking_V2 { 32 | vector sums; 33 | 34 | void getAllSubestsSum(vector& nums, int N, int currSum, int startIdx) { 35 | sums.push_back(currSum); 36 | for(int J=startIdx; J subsetSums(vector& nums, int N) { 44 | getAllSubestsSum(nums, N, 0, 0); 45 | return sums; 46 | } 47 | }; 48 | 49 | // Driver code 50 | int main() { 51 | // Tracks the user wants to perform the operation or not 52 | bool userWantsOperation = true; 53 | 54 | while(userWantsOperation) { 55 | // Controls console clearance for both "windows" and "linux" user 56 | system("cls || clear"); 57 | 58 | // Input the array size 59 | int N; 60 | cout<<"Enter the size of array: "; 61 | cin>>N; 62 | 63 | // Check the given size is valid or not 64 | if(N <= 0) { 65 | cout<<"Enter a valid size, application expects a positive integer!"; 66 | return 0; 67 | } 68 | 69 | // Stores the array values 70 | vector nums(N, 0); 71 | 72 | // Input the array values 73 | cout<<"Enter values of the array: "; 74 | for(int J = 0; J < N; ++J) { 75 | cin>>nums[J]; 76 | } 77 | 78 | // Call to get the list of sums 79 | Backtracking_V2 bt; 80 | vector sums = bt.subsetSums(nums, N); 81 | 82 | // Print values 83 | cout<<"List of all the subsets: "; 84 | for(int sum : sums) 85 | cout<>userChoice; 91 | userWantsOperation = (userChoice == 'R' ? true : false); 92 | } 93 | 94 | return 0; 95 | } 96 | /* 97 | Topics: Array | Backtracking 98 | Link: https://www.geeksforgeeks.org/problems/subset-sums2234/1 99 | */ 100 | -------------------------------------------------------------------------------- /String/Reverse Words in a String III.cpp: -------------------------------------------------------------------------------- 1 | // Program to reverse the order of characters in each word within a sentence while still preserving whitespace and initial word order ~ coded by Hiren 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // Solution class: 7 | class Solution { 8 | public: 9 | // #1 Method to reverse the words of a string, using 1 stack - O(N) & O(N) 10 | string reverseWords_V1(const string& s) { 11 | int n = s.length(); 12 | 13 | stack st; // Stores the word in reverse order 14 | string output = ""; // Stores the resultant string (output) 15 | 16 | // Iterate and store the words to the stack 17 | for(int i=0; i= start) 55 | output.push_back(s[tmp--]); 56 | 57 | output.push_back(' '); 58 | start = end + 1; 59 | } 60 | 61 | // Remove the additional single space 62 | output.pop_back(); 63 | 64 | // Return the resultant string (output) 65 | return output; 66 | } 67 | }; 68 | 69 | // Driver code 70 | int main() { 71 | cout<<"Enter the number of testcases: "; 72 | int testCases; 73 | cin>>testCases; 74 | cin.ignore(); // Ignore the newline character left in the input buffer. 75 | 76 | if(testCases <= 0) { 77 | cout<<"Enter a valid number for the testcases, application expects a positive integer!"; 78 | return 0; 79 | } 80 | 81 | while(testCases--) { 82 | string s; 83 | cout<<"\nEnter a sentence: "; getline(cin, s); 84 | Solution solution; 85 | string output = solution.reverseWords_V2(s); 86 | cout<<"Sentence after words reversal: "<& dp, int n) { 22 | if(n == 1) 23 | return 0; 24 | 25 | if(dp[n] != -1) 26 | return dp[n]; 27 | 28 | int minSteps = solveWithMemo(dp, n - 1); 29 | 30 | for(int divisor = 2; divisor <= 3; ++divisor) 31 | if(n % divisor == 0) 32 | minSteps = minSteps = min(minSteps, solveWithMemo(dp, n / divisor)); 33 | 34 | return dp[n] = minSteps + 1; 35 | } 36 | 37 | public: 38 | int minStepsToMakeOne(int n) { 39 | vector dp(n + 1, -1); 40 | return solveWithMemo(dp, n); 41 | } 42 | }; 43 | // Note: In the previous approach, we're writing the same logic through redundant conditions so instead of doing that here I just generalized them into the loop 44 | 45 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 46 | 47 | class BottomUp { 48 | public: 49 | // O(N) & O(N) : Where N = given_n 50 | int minStepsToMakeOne(int given_n) { 51 | vector dp(given_n + 1, -1); 52 | dp[1] = 0; 53 | 54 | for(int n = 2; n <= given_n; ++n) { 55 | int minSteps = dp[n - 1]; 56 | 57 | for(int divisor = 2; divisor <= 3; ++divisor) { 58 | if(n % divisor == 0) { 59 | minSteps = minSteps = min(minSteps, dp[n / divisor]); 60 | } 61 | } 62 | 63 | dp[n] = minSteps + 1; 64 | } 65 | 66 | return dp[given_n]; 67 | } 68 | }; 69 | 70 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 71 | 72 | Topics: Array | Dynamic Programming 73 | Links : https://leetcode.com/discuss/interview-question/538568/google-onsite-min-operations-to-reduce-number-to-1 74 | https://www.geeksforgeeks.org/problems/minimum-steps-to-minimize-n-as-per-given-condition0618/0 75 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/8 - House Robber/House Robber.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the maximum amount of money that you can rob tonight without alerting the police ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(2^N) & O(N) 9 | int solveWithoutMemo(const vector& nums, int idx) { 10 | if(idx >= n) 11 | return 0; // If no houses then can rob no money 12 | 13 | int robHouse = nums[idx] + solveWithoutMemo(nums, idx + 2); 14 | int skipHouse = solveWithoutMemo(nums, idx + 1); 15 | 16 | return max(robHouse, skipHouse); 17 | } 18 | 19 | // O(2*N) & O(2*N) 20 | int solveWithMemo(vector& dp, const vector& nums, int idx) { 21 | if(idx >= n) 22 | return 0; // If no houses then can rob no money 23 | 24 | if(dp[idx] != -1) 25 | return dp[idx]; 26 | 27 | int robHouse = nums[idx] + solveWithMemo(dp, nums, idx + 2); 28 | int skipHouse = solveWithMemo(dp, nums, idx + 1); 29 | 30 | return dp[idx] = max(robHouse, skipHouse); 31 | } 32 | 33 | public: 34 | // Methot to find maximum money can rob, using recursion with memoization - O(N) & O(N) 35 | int robMaxMoney(vector& nums) { 36 | n = nums.size(); 37 | vector dp(n, -1); 38 | return solveWithMemo(dp, nums, 0); 39 | } 40 | }; 41 | 42 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 43 | 44 | class BottomUp { 45 | int n; 46 | 47 | // O(1*N) & O(1*N) 48 | int solveWith1DTable(const vector& nums) { 49 | vector dp(n + 2, -1); 50 | dp[n] = 0; 51 | dp[n + 1] = 0; 52 | 53 | for(int idx = n-1; idx >= 0; --idx) { 54 | int robHouse = nums[idx] + dp[idx + 2]; 55 | int skipHouse = dp[idx + 1]; 56 | dp[idx] = max(robHouse, skipHouse); 57 | } 58 | 59 | return dp[0]; 60 | } 61 | 62 | // O(1*N) & O(1) 63 | int solveWithoutTable(const vector& nums) { 64 | int dp_idx_1 = 0; 65 | int dp_idx_2 = 0; 66 | int dp_idx = 0; 67 | 68 | for(int idx = n-1; idx >= 0; --idx) { 69 | int robHouse = nums[idx] + dp_idx_2; 70 | int skipHouse = dp_idx_1; 71 | dp_idx = max(robHouse, skipHouse); 72 | dp_idx_2 = dp_idx_1; 73 | dp_idx_1 = dp_idx; 74 | } 75 | 76 | return dp_idx; 77 | } 78 | 79 | public: 80 | int robMaxMoney(vector& nums) { 81 | n = nums.size(); 82 | return solveWithoutTable(nums); 83 | } 84 | }; 85 | 86 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 87 | 88 | Topics: Array | Dynamic Programming 89 | Links : https://leetcode.com/problems/house-robber/description/?envType=daily-question&envId=2024-01-21 90 | https://www.naukri.com/code360/problems/loot-houses_630510 91 | https://www.geeksforgeeks.org/problems/stickler-theif-1587115621/1?itm_source=geeksforgeeks&itm_medium=article&itm_campaign=bottom_sticky_on_article 92 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/7 - Minimum Cost Climbing Stairs/Minimum Cost Climbing Stairs.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum cost to reach the top of the floor ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(2^N) & O(N) 9 | int solveWithoutMemo(const vector& cost, int idx) { 10 | if(idx >= n) 11 | return 0; // If no steps left 12 | 13 | int climb1Step = solveWithoutMemo(cost, idx + 1); 14 | int climb2Step = solveWithoutMemo(cost, idx + 2); 15 | 16 | return cost[idx] + min(climb1Step, climb2Step); 17 | } 18 | 19 | // O(2*N) & O(2*N) 20 | int solveWithMemo(vector& dp, const vector& cost, int idx) { 21 | if(idx >= n) 22 | return 0; // If no steps left 23 | 24 | if(dp[idx] != -1) 25 | return dp[idx]; 26 | 27 | int climb1Step = solveWithMemo(dp, cost, idx + 1); 28 | int climb2Step = solveWithMemo(dp, cost, idx + 2); 29 | 30 | return dp[idx] = cost[idx] + min(climb1Step, climb2Step); 31 | } 32 | 33 | public: 34 | // Method to find minimum cost to reach top, using recursion with memoization - O(N) & O(N) 35 | int minCostToReachTop(vector& cost) { 36 | n = cost.size(); 37 | vector dp1(n, -1), dp2(n, -1); 38 | int startFrom0 = solveWithMemo(dp1, cost, 0); 39 | int startFrom1 = solveWithMemo(dp2, cost, 1); 40 | return min(startFrom0, startFrom1); 41 | } 42 | }; 43 | 44 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 45 | 46 | class BottomUp { 47 | int n; 48 | 49 | // O(1*N) & O(1*N) 50 | int solveWith1DTable(const vector& cost, int start) { 51 | vector dp(n + 2, -1); 52 | dp[n] = 0; 53 | dp[n + 1] = 0; 54 | 55 | for(int idx = n - 1; idx >= start; --idx) { 56 | int climb1Step = dp[idx + 1]; 57 | int climb2Step = dp[idx + 2]; 58 | dp[idx] = cost[idx] + min(climb1Step, climb2Step); 59 | } 60 | 61 | return dp[start]; 62 | } 63 | 64 | // O(1*N) & O(1) 65 | int solveWithoutTable(const vector& cost, int start) { 66 | int dp_idx_1 = 0; 67 | int dp_idx_2 = 0; 68 | int dp_idx = 0; 69 | 70 | for(int idx = n - 1; idx >= start; --idx) { 71 | int climb1Step = dp_idx_1; 72 | int climb2Step = dp_idx_2; 73 | dp_idx = cost[idx] + min(climb1Step, climb2Step); 74 | dp_idx_2 = dp_idx_1; 75 | dp_idx_1 = dp_idx; 76 | } 77 | 78 | return dp_idx; 79 | } 80 | 81 | public: 82 | int minCostToReachTop(vector& cost) { 83 | n = cost.size(); 84 | int startFrom0 = solveWithoutTable(cost, 0); 85 | int startFrom1 = solveWithoutTable(cost, 1); 86 | return min(startFrom0, startFrom1); 87 | } 88 | }; 89 | 90 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 91 | 92 | Topics: Array | Dynamic Programming 93 | Link : https://leetcode.com/problems/min-cost-climbing-stairs/description/ 94 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/9 - House Robber II/House Robber II.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the maximum amount of money that you can rob tonight without alerting the police ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(2^N) & O(N) 7 | int solveWithoutMemo(const vector& nums, int start, const int end) { 8 | if(start > end) 9 | return 0; 10 | 11 | int robHouse = nums[start] + solveWithoutMemo(nums, start + 2, end); 12 | int skipHouse = solveWithoutMemo(nums, start + 1, end); 13 | 14 | return max(robHouse, skipHouse); 15 | } 16 | 17 | // O(2*N) & O(2*N) 18 | int solveWithMemo(vector& dp, const vector& nums, int start, const int end) { 19 | if(start > end) 20 | return 0; 21 | 22 | if(dp[start] != -1) 23 | return dp[start]; 24 | 25 | int robHouse = nums[start] + solveWithMemo(dp, nums, start + 2, end); 26 | int skipHouse = solveWithMemo(dp, nums, start + 1, end); 27 | 28 | return dp[start] = max(robHouse, skipHouse); 29 | } 30 | 31 | public: 32 | // Methot to find maximum money can rob, using recursion with memoization - O(N) & O(N) 33 | int robMaxMoney(vector& nums) { 34 | const int n = nums.size(); 35 | if(n == 1) return nums[0]; 36 | vector dp1(n - 1, -1), dp2(n, -1); 37 | int startFrom0 = solveWithMemo(dp1, nums, 0, n - 2); 38 | int startFrom1 = solveWithMemo(dp2, nums, 1, n - 1); 39 | return max(startFrom0, startFrom1); 40 | } 41 | }; 42 | 43 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 44 | 45 | class BottomUp { 46 | // O(1*N) & O(1*N) 47 | int solveWith1DTable(const vector& nums, int start, const int end) { 48 | vector dp(end + 3, -1); 49 | dp[end + 2] = 0; 50 | dp[end + 1] = 0; 51 | 52 | for(int idx = end; idx >= start; --idx) { 53 | int robHouse = nums[idx] + dp[idx + 2]; 54 | int skipHouse = dp[idx + 1]; 55 | dp[idx] = max(robHouse, skipHouse); 56 | } 57 | 58 | return dp[start]; 59 | } 60 | 61 | // O(1*N) & O(1) 62 | int solveWithoutTable(const vector& nums, int start, const int end) { 63 | int dp_idx_2 = 0; 64 | int dp_idx_1 = 0; 65 | int dp_idx = 0; 66 | 67 | for(int idx = end; idx >= start; --idx) { 68 | int robHouse = nums[idx] + dp_idx_2; 69 | int skipHouse = dp_idx_1; 70 | dp_idx = max(robHouse, skipHouse); 71 | dp_idx_2 = dp_idx_1; 72 | dp_idx_1 = dp_idx; 73 | } 74 | 75 | return dp_idx; 76 | } 77 | 78 | public: 79 | int robMaxMoney(vector& nums) { 80 | const int n = nums.size(); 81 | if(n == 1) return nums[0]; 82 | int startFrom0 = solveWithoutTable(nums, 0, n - 2); 83 | int startFrom1 = solveWithoutTable(nums, 1, n - 1); 84 | return max(startFrom0, startFrom1); 85 | } 86 | }; 87 | 88 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 89 | 90 | Topics: Array | Dynamic Programming 91 | Link : https://leetcode.com/problems/house-robber-ii/ 92 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/3 - Consecutive Ones Not Allowed/Consecutive Ones Not Allowed.cpp: -------------------------------------------------------------------------------- 1 | // Code to count all the possible distinct binary strings of length n such that there are no consecutive 1’s ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | /* 5 | NOTE: The solution of this problem is totally same as the first one (Fibonacci Number). The edge case in the only change. 6 | */ 7 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 8 | 9 | class TopDown { 10 | // O(2^N) & O(N) 11 | int solveWithoutMemo(int n) { 12 | if(n < 3) 13 | return n; 14 | 15 | int prevNum1 = solveWithoutMemo(n - 1); 16 | int prevNum2 = solveWithoutMemo(n - 2); 17 | 18 | return prevNum1 + prevNum2; 19 | } 20 | 21 | // O(2*N) & O(2*N) 22 | int solveWithMemo(vector& dp, int n) { 23 | if(n < 3) 24 | return n; 25 | 26 | if(dp[n] != -1) 27 | return dp[n]; 28 | 29 | int prevNum1 = solveWithMemo(dp, n - 1); 30 | int prevNum2 = solveWithMemo(dp, n - 2); 31 | 32 | return dp[n] = (prevNum1 + prevNum2); 33 | } 34 | 35 | public: 36 | int countDistinctBinaryStrs(int n) { 37 | vector dp(n + 2, -1); 38 | return solveWithMemo(dp, n + 1); // The main task is to find the n + 1th number of the fibonacci sequence 39 | } 40 | }; 41 | 42 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 43 | 44 | class BottomUp { 45 | // O(1*N) & O(1*N) 46 | int solveWith1DTable(int n) { 47 | vector dp(n + 2, -1); 48 | 49 | // Initialize the edge case 50 | dp[0] = 0; 51 | dp[1] = 1; 52 | dp[2] = 2; 53 | 54 | for(int i = 3; i <= n+1; ++i) { 55 | int prevNum1 = dp[i - 1]; 56 | int prevNum2 = dp[i - 2]; 57 | dp[i] = (prevNum1 + prevNum2); 58 | } 59 | 60 | return dp[n + 1]; 61 | } 62 | 63 | // O(1*N) & O(1) 64 | int solveWithoutTable(int n) { 65 | int prevNum2 = 1; 66 | int prevNum1 = 2; 67 | int currNum = (n == 1) ? 2 : 3; // Handle when n = 1 and n = 2, as the loop is not going to work for them 68 | 69 | for(int i = 3; i <= n+1; ++i) { 70 | currNum = prevNum1 + prevNum2; 71 | prevNum2 = prevNum1; 72 | prevNum1 = currNum; 73 | } 74 | 75 | return currNum; 76 | } 77 | 78 | public: 79 | int countDistinctBinaryStrs(int n) { 80 | return solveWithoutTable(n); 81 | } 82 | }; 83 | 84 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 85 | /* 86 | NOTE: This same question is also in the Multi-Dimensional DP Folder, but there I solved it using 2D DP approach that came to my mind. 87 | Eventually you'll see, just keep doing it. 88 | */ 89 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 90 | 91 | Topics: Array | Dynamic Programming 92 | Link : https://www.geeksforgeeks.org/problems/consecutive-1s-not-allowed1912/1 93 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/18 - Taking Maximum Energy From The Mystic Dungeon/Taking Maximum Energy From The Mystic Dungeon.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the maximum possible energy you can gain by performing the specified teleportation ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N*N) & O(N) 9 | int solveWithoutMemo(vector& energy, int k, int magician) { 10 | if(magician >= n) 11 | return 0; 12 | 13 | return energy[magician] + solveWithoutMemo(energy, k, magician + k); 14 | } 15 | // Note: In the time complexity of `solveWithoutMemo()`, the first term in O(N*N) is O(N) and this time is considered for the loop through which we're calling this function 16 | 17 | // O(2*N) & O(2*N) 18 | int solveWithMemo(vector& dp, vector& energy, int k, int magician) { 19 | if(magician >= n) 20 | return 0; 21 | 22 | if(dp[magician] != -1) 23 | return dp[magician]; 24 | 25 | return dp[magician] = energy[magician] + solveWithMemo(dp, energy, k, magician + k); 26 | } 27 | // Note: In the time complexity of `solveWithMemo()`, a term in O(2*N) is O(1*N) and this time is considered for the loop through which we're calling this function 28 | 29 | public: 30 | int maximumEnergy(vector& energy, int k) { 31 | n = energy.size(); 32 | 33 | vector dp(n, -1); 34 | 35 | int maxEnergy = INT_MIN; 36 | for(int start = 0; start < n; ++start) 37 | maxEnergy = max(maxEnergy, solveWithMemo(dp, energy, k, start)); 38 | 39 | return maxEnergy; 40 | } 41 | }; 42 | 43 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 44 | 45 | class BottomUp { 46 | int n; 47 | 48 | // O(2*N) & O(1*N) 49 | int solveWith1DTable(vector& energy, int k) { 50 | vector dp(n, -1); 51 | for(int magician = n-1; magician >= 0; --magician) { 52 | int nextAbsorptions = (magician + k < n) ? dp[magician + k] : 0; 53 | dp[magician] = energy[magician] + nextAbsorptions; 54 | } 55 | 56 | int maxEnergy = INT_MIN; 57 | for(int start = 0; start < n; ++start) 58 | maxEnergy = max(maxEnergy, dp[start]); 59 | 60 | return maxEnergy; 61 | } 62 | 63 | // O(1*N) & O(1*N) 64 | int solveWith1DEnhanced(vector& energy, int k) { 65 | vector dp(n, -1); 66 | 67 | int maxEnergy = INT_MIN; 68 | for(int magician = n-1; magician >= 0; --magician) { 69 | int nextAbsorptions = (magician + k < n) ? dp[magician + k] : 0; 70 | dp[magician] = energy[magician] + nextAbsorptions; 71 | maxEnergy = max(maxEnergy, dp[magician]); 72 | } 73 | 74 | return maxEnergy; 75 | } 76 | 77 | public: 78 | int maximumEnergy(vector& energy, int k) { 79 | n = energy.size(); 80 | return solveWith1DEnhanced(energy, k); 81 | } 82 | }; 83 | 84 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 85 | 86 | Topics: Array | Prefix Sum | Dynamic Programming 87 | Link : https://leetcode.com/problems/taking-maximum-energy-from-the-mystic-dungeon/description/ 88 | -------------------------------------------------------------------------------- /Dynamic Programming/Tree DP/3 - Linked List in Binary Tree.cpp: -------------------------------------------------------------------------------- 1 | // Code to check is if all the elements in the linked list starting from the head correspond to some downward path connected in the binary tree, otherwise return false. In this context downward path means a path that starts at some node and goes downwards ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 4 | 5 | // Class to implement the Top-down approach: 6 | class DynamicProgramming { 7 | map, bool> dp; 8 | ListNode* origHead = nullptr; 9 | 10 | // O((M*N)Log(M*N)) & O(M*N + H) : Where M is the length of the list. N and H is the number of nodes and height of the tree 11 | bool solveWithMemo(ListNode* headNode, TreeNode* rootNode) { 12 | // Edge case: If the list is empty then return true 13 | if(!headNode) 14 | return true; 15 | 16 | // Edge case: At this point if the tree is empty then return false 17 | if(!rootNode) 18 | return false; 19 | 20 | // Memoization table: If the current state is already computed then return the computed value 21 | if(dp.count({headNode, rootNode})) 22 | return dp[{headNode, rootNode}]; 23 | 24 | // If the value of tree node and list node is equal 25 | if(rootNode->val == headNode->val) { 26 | // If its the last node of the list then return true 27 | if(!headNode->next) 28 | return dp[{headNode, rootNode}] = true; 29 | 30 | // If the value of left child is equal to the next node of list then check the existence of the remaining list at the left subtree 31 | if(rootNode->left && headNode->next->val == rootNode->left->val && solveWithMemo(headNode->next, rootNode->left)) 32 | return dp[{headNode, rootNode}] = true; 33 | 34 | // If the value of right child is equal to the next node of list then check the existence of the remaining list at the right subtree 35 | if(rootNode->right && headNode->next->val == rootNode->right->val && solveWithMemo(headNode->next, rootNode->right)) 36 | return dp[{headNode, rootNode}] = true; 37 | } 38 | 39 | // Check the existence of the list from its first node at the left and right side of the tree node 40 | bool isPathFromLeft = solveWithMemo(origHead, rootNode->left); 41 | bool isPathFromRight = solveWithMemo(origHead, rootNode->right); 42 | 43 | // Store the result value to the memoization table and then return it 44 | return dp[{headNode, rootNode}] = isPathFromLeft || isPathFromRight; 45 | } 46 | 47 | public: 48 | // Method to check is if linked list present in the binary tree, using recursion with memoization :- 49 | bool isSubPath(ListNode* headNode, TreeNode* rootNode) { 50 | origHead = headNode; 51 | return solveWithMemo(headNode, rootNode); 52 | } 53 | }; 54 | 55 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 56 | 57 | Topics: Linked List | Tree | Depth-First Search | Binary Tree | Dynamic Programming 58 | Link : https://leetcode.com/problems/linked-list-in-binary-tree/description/ 59 | -------------------------------------------------------------------------------- /Greedy/Divide Array Into Arrays With Max Difference.cpp: -------------------------------------------------------------------------------- 1 | // Program to divide the array into one or more arrays of size 3 satisfying the specified conditions ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // Solution class: 9 | class Solution { 10 | public: 11 | // Method to divide the array into one or more arrays of size 3, using sorting - O(NLogN) & O(1) : Where N is the size of the array. 12 | vector> divideArray(vector& nums, int k) { 13 | int n = nums.size(); 14 | 15 | // Edge case: When the size of the array is not a multiple of 3 then its not possible to divide the array 16 | if(n % 3 != 0) 17 | return {}; 18 | 19 | sort(begin(nums), end(nums)); // Sort the array to handle the specified conditions more easily 20 | vector> arrays; // Stores the resultant arrays 21 | 22 | // Iterate the array 23 | for(int i=0; i k) 27 | return {}; 28 | // If reached here, then its possible to divide the array, store the 3 values as an array 29 | arrays.push_back({num1, num2, num3}); 30 | } 31 | 32 | // Return the 2d array containing the resultant arrays 33 | return arrays; 34 | } 35 | }; 36 | 37 | // Driver code 38 | int main() { 39 | // Tracks the user wants to perform the operation or not 40 | bool canPerformOperation = true; 41 | 42 | while(canPerformOperation) { 43 | // Handles console clearance for both "windows" and "linux" user 44 | system("cls || clear"); 45 | 46 | // Input the size of the array 47 | int size; 48 | cout<<"Enter the size of the array: "; 49 | cin>>size; 50 | 51 | // Check the given size is valid or not 52 | if(size <= 0) { 53 | cout<<"Enter a valid size, application expects a positive integer!"; 54 | return 0; 55 | } 56 | 57 | vector nums(size, 0); 58 | 59 | // Input the values of the array 60 | for(int i=0; i>nums[i]; 63 | } 64 | 65 | // Input the value of k 66 | int k; 67 | cout<<"\nEnter the value of k: "; 68 | cin>>k; 69 | 70 | // Call to divide the array 71 | Solution solution; 72 | vector> arrays = solution.divideArray(nums, k); 73 | 74 | // Print values 75 | for(auto& array : arrays) { 76 | cout<<"["; 77 | for(int i=0; i<3; i++) { 78 | cout<>userChoise; 88 | canPerformOperation = (userChoise == 'Y') ? true : false ; 89 | } 90 | 91 | return 0; 92 | } 93 | /* 94 | Topics: Array | Sorting | Greedy 95 | Link: https://leetcode.com/problems/divide-array-into-arrays-with-max-difference/description/?envType=daily-question&envId=2024-02-01 96 | */ 97 | -------------------------------------------------------------------------------- /String/Minimum Number Of Steps To Make Two Strings Anagram.cpp: -------------------------------------------------------------------------------- 1 | // Program to find the minimum number of steps required to make the two strings anagram ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | // Solution class: 8 | class Solution { 9 | public: 10 | // #1 Method to find the minimum number of steps, using (stl) map - O(N) & O(1) : Where N is size of the string "s" (s1.size == s2.size) 11 | int minSteps_V1(const std::string& s, const std::string& t) { 12 | // Stores the letters with their frequencies 13 | std::unordered_map mp; 14 | 15 | // Iterate the string "s" and map the letters with their frequencies 16 | for(char ch : s) 17 | mp[ch]++; 18 | 19 | // Iterate the string "t" and reduce the frequency of the letters which are also present in string "s" 20 | for(char ch : t) 21 | mp[ch]--; 22 | 23 | // Stores the minimum number of steps (resultant value) 24 | int output = 0; 25 | 26 | // Iterate and count the resultant value 27 | for(auto [ch, count] : mp) 28 | output += (count > 0) ? count : 0; 29 | 30 | // Return the minimum number of steps (resultant value) 31 | return output; 32 | } 33 | 34 | // #2 Method to find the minimum number of steps, using buffer only - O(N) & O(1) : Where N is size of the string "s" (s1.size == s2.size) 35 | int minSteps_V2(const std::string& s, const std::string& t) { 36 | int n = s.size(); 37 | 38 | // Stores the frequencies of the letters at their corresponding index 39 | std::vector mp(26); 40 | 41 | // Iterate the strings 42 | for(int i=0; i 0) ? count : 0; 52 | 53 | // Return the minimum number of steps (resultant value) 54 | return output; 55 | } 56 | }; 57 | 58 | // Driver code 59 | int main() { 60 | // Tracks for the user wants to perform the operation or not 61 | bool canPerformOperation = true; 62 | 63 | while(canPerformOperation) { 64 | // Handles console clearence for both "windows" and "linux" user 65 | system("cls || clear"); 66 | 67 | // Input section for strings 68 | std::string s, t; 69 | std::cout<<"Enter the first string: " ; std::cin>>s; 70 | std::cout<<"Enter the second string: "; std::cin>>t; 71 | 72 | // Call to find the minimum number of steps 73 | Solution solution; 74 | int output = solution.minSteps_V2(s, t); 75 | std::cout<<"The minimum number of steps needed to make \""<>userChoise; 81 | canPerformOperation = (userChoise == 'R' ? true : false); 82 | } 83 | 84 | return 0; 85 | } 86 | /* 87 | Topics: Hash Table | String | Counting 88 | Link: https://leetcode.com/problems/minimum-number-of-steps-to-make-two-strings-anagram/description/ 89 | */ 90 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/23 - Coin Change/23.1 - Coin Change (Without Sorting).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the fewest number of coins that you need to make up the amount. If that amount of money cannot be made up by any combination of the coins then return -1. You may assume that you have an infinite number of each kind of coin ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N^A) & O(A) : Where A = amount 9 | int solveWithoutMemo(const vector& coins, int amount) { 10 | if(amount == 0) 11 | return 0; 12 | 13 | int minCoins = INT_MAX; 14 | 15 | for(int i = 0; i < n; ++i) { 16 | if(coins[i] > amount) 17 | continue; 18 | int nextCoins = solveWithoutMemo(coins, amount - coins[i]); 19 | if(nextCoins != INT_MAX) minCoins = min(minCoins, nextCoins + 1); 20 | } 21 | 22 | return minCoins; 23 | } 24 | 25 | // O(N*A) & O(2*A) : Where A = amount 26 | int solveWithMemo(vector& dp, const vector& coins, int amount) { 27 | if(amount == 0) 28 | return 0; 29 | 30 | if(dp[amount] != -1) 31 | return dp[amount]; 32 | 33 | int minCoins = INT_MAX; 34 | 35 | for(int i = 0; i < n; ++i) { 36 | if(coins[i] > amount) 37 | continue; 38 | int nextCoins = solveWithMemo(dp, coins, amount - coins[i]); 39 | if(nextCoins != INT_MAX) minCoins = min(minCoins, nextCoins + 1); 40 | } 41 | 42 | return dp[amount] = minCoins; 43 | } 44 | 45 | public: 46 | int minCoinsToMakeAmount(vector& coins, int amount) { 47 | n = coins.size(); 48 | vector dp(amount + 1, -1); 49 | int minCoins = solveWithMemo(dp, coins, amount); 50 | return (minCoins == INT_MAX) ? -1 : minCoins; 51 | } 52 | }; 53 | 54 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 55 | 56 | class BottomUp { 57 | public: 58 | // O(A*N) & O(1*A) : Where A = givenAmount 59 | int minCoinsToMakeAmount(const vector& coins, int givenAmount) { 60 | int n = coins.size(); 61 | 62 | vector dp(givenAmount + 1, -1); 63 | dp[0] = 0; 64 | 65 | for(int amount = 1; amount <= givenAmount; ++amount) { 66 | int minCoins = INT_MAX; 67 | 68 | for(int i = 0; i < n; ++i) { 69 | if(coins[i] > amount) 70 | continue; 71 | int nextCoins = dp[amount - coins[i]]; 72 | if(nextCoins != INT_MAX) minCoins = min(minCoins, nextCoins + 1); 73 | } 74 | 75 | dp[amount] = minCoins; 76 | } 77 | 78 | int minCoins = dp[givenAmount]; 79 | return (minCoins == INT_MAX) ? -1 : minCoins; 80 | } 81 | }; 82 | 83 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 84 | 85 | Topics: Array | Dynamic Programming 86 | Links : https://leetcode.com/problems/coin-change/description/ 87 | https://cses.fi/problemset/task/1634 88 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/26 - Dice Combinations/Dice Combinations.cpp: -------------------------------------------------------------------------------- 1 | // Code to count the number of ways to construct sum n by throwing a dice one or more times. Each throw produces an outcome between 1 and 6 ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | const int MOD = 1e9 + 7; 7 | 8 | // O(6^N) & O(N) 9 | int solveWithoutMemo(int n) { 10 | if(n == 0) 11 | return 1; 12 | 13 | int count = 0; 14 | 15 | for(int outcome = 1; (outcome <= 6 && outcome <= n); ++outcome) 16 | count = (count + solveWithoutMemo(n - outcome)) % MOD; 17 | 18 | return count; 19 | } 20 | 21 | // O(6*N) & O(2*N) 22 | int solveWithMemo(vector& dp, int n) { 23 | if(n == 0) 24 | return 1; 25 | 26 | if(dp[n] != -1) 27 | return dp[n]; 28 | 29 | int count = 0; 30 | 31 | for(int outcome = 1; (outcome <= 6 && outcome <= n); ++outcome) 32 | count = (count + solveWithMemo(dp, n - outcome)) % MOD; 33 | 34 | return dp[n] = count; 35 | } 36 | 37 | public: 38 | int numWays(int n) { 39 | vector dp(n + 1, -1); 40 | return solveWithMemo(dp, n); 41 | } 42 | }; 43 | 44 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 45 | 46 | class BottomUp { 47 | const int MOD = 1e9 + 7; 48 | 49 | // O(N*6) & O(1*N) : Where N = given_n 50 | int solveWith1DTable(int given_n) { 51 | vector dp(given_n + 1, -1); 52 | dp[0] = 1; 53 | 54 | for(int n = 1; n <= given_n; ++n) { 55 | int count = 0; 56 | 57 | for(int outcome = 1; (outcome <= 6 && outcome <= n); ++outcome) { 58 | count = (count + dp[n - outcome]) % MOD; 59 | } 60 | 61 | dp[n] = count; 62 | } 63 | 64 | return dp[given_n]; 65 | } 66 | 67 | // O(N*6) & O(1) : Where N = given_n 68 | int solveWithoutTable(int given_n) { 69 | int dp_n_1 = 1; // dp[n - 1] 70 | int dp_n_2 = 0; // dp[n - 2] 71 | int dp_n_3 = 0; // dp[n - 3] 72 | int dp_n_4 = 0; // dp[n - 4] 73 | int dp_n_5 = 0; // dp[n - 5] 74 | int dp_n_6 = 0; // dp[n - 6] 75 | int dp_n = 1; // dp[n] 76 | 77 | for(int n = 1; n <= given_n; ++n) { 78 | int count = 0; 79 | count = (count + dp_n_1) % MOD; 80 | count = (count + dp_n_2) % MOD; 81 | count = (count + dp_n_3) % MOD; 82 | count = (count + dp_n_4) % MOD; 83 | count = (count + dp_n_5) % MOD; 84 | count = (count + dp_n_6) % MOD; 85 | dp_n = count; 86 | 87 | dp_n_6 = dp_n_5; 88 | dp_n_5 = dp_n_4; 89 | dp_n_4 = dp_n_3; 90 | dp_n_3 = dp_n_2; 91 | dp_n_2 = dp_n_1; 92 | dp_n_1 = dp_n; 93 | } 94 | 95 | return dp_n; 96 | } 97 | 98 | public: 99 | int numWays(int n) { 100 | return solveWithoutTable(n); 101 | } 102 | }; 103 | 104 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 105 | 106 | Topics: Array | Dynamic Programming | Combinatorics 107 | Link : https://cses.fi/problemset/task/1633 108 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/5 - Count Number of Hops/Count Number of Hops.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the total number of ways the frog can take to reach the top of the nth step, a frog can jump either 1, 2, or 3 steps to go to the top ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(3^N) & O(N) 7 | int solveWithoutMemo(int n) { 8 | if(n <= 0) 9 | return (n == 0); // Edge case: If n becomes 0 then you've 1 way 10 | 11 | // There are three possibilities to reach this nth step 12 | int jump1Step = solveWithoutMemo(n - 1); // To make 1 jump from any step below it 13 | int jump2Step = solveWithoutMemo(n - 2); // To make 2 jump from any step below it 14 | int jump3Step = solveWithoutMemo(n - 3); // To make 3 jump from any step below it 15 | 16 | // Return total number of ways exists to reach this nth step 17 | return jump1Step + jump2Step + jump3Step; 18 | } 19 | 20 | // O(3*N) & O(2*N) 21 | int solveWithMemo(vector& memory, int n) { 22 | if(n <= 0) 23 | return (n == 0); // Edge case: If n becomes 0 then you've 1 way 24 | 25 | if(memory[n] != -1) 26 | return memory[n]; 27 | 28 | // There are three possibilities to reach this nth step 29 | int jump1Step = solveWithMemo(memory, n - 1); // To make 1 jump from any step below it 30 | int jump2Step = solveWithMemo(memory, n - 2); // To make 2 jump from any step below it 31 | int jump3Step = solveWithMemo(memory, n - 3); // To make 3 jump from any step below it 32 | 33 | // Store the result to memoization table and then return it 34 | return memory[n] = (jump1Step + jump2Step + jump3Step); 35 | } 36 | 37 | public: 38 | int numWaysToReachTop(int n) { 39 | vector memory(n + 1, -1); 40 | return solveWithMemo(memory, n); 41 | } 42 | }; 43 | 44 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 45 | 46 | class BottomUp { 47 | // O(1*N) & O(1*N) 48 | int solveWith1DTable(int n) { 49 | vector dp(n + 1, -1); 50 | dp[0] = 1; // Init the edge case 51 | 52 | for(int i = 1; i <= n; ++i) { 53 | int jump1Step = dp[i - 1]; 54 | int jump2Step = (i - 2 >= 0) ? dp[i - 2] : 0; 55 | int jump3Step = (i - 3 >= 0) ? dp[i - 3] : 0; 56 | dp[i] = jump1Step + jump2Step + jump3Step; 57 | } 58 | 59 | return dp[n]; 60 | } 61 | 62 | // O(1*N) & O(1) 63 | int solveWithoutTable(int n) { 64 | int jump1Step = 1; 65 | int jump2Step = 0; 66 | int jump3Step = 0; 67 | int numWays = 0; 68 | 69 | for(int i = 1; i <= n; ++i) { 70 | numWays = jump1Step + jump2Step + jump3Step; 71 | jump3Step = jump2Step; 72 | jump2Step = jump1Step; 73 | jump1Step = numWays; 74 | } 75 | 76 | return numWays; 77 | } 78 | 79 | public: 80 | int numWaysToReachTop(int n) { 81 | return solveWithoutTable(n); 82 | } 83 | }; 84 | 85 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 86 | 87 | Topics: Array | Dynamic Programming 88 | Link : https://www.geeksforgeeks.org/problems/count-number-of-hops-1587115620/1 89 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/22 - Maximum Number Of Jumps To Reach The Last Index/Maximum Number Of Jumps To Reach The Last Index.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the maximum number of jumps required to reach the last index of the array with following the mentioned rules ~ coded by Hiren 2 | 3 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N^N) & O(N) 9 | int solveWithoutMemo(vector& nums, int target, int start) { 10 | if(start == n-1) 11 | return 0; 12 | 13 | int maxJumps = INT_MIN; 14 | 15 | for(int jumpIdx = start+1; jumpIdx < n; ++jumpIdx) { 16 | int delta = nums[jumpIdx] - nums[start]; 17 | 18 | if(-target <= delta && delta <= target) { 19 | int nextJumps = solveWithoutMemo(nums, target, jumpIdx); 20 | if(nextJumps != INT_MIN) { 21 | maxJumps = max(maxJumps, nextJumps + 1); 22 | } 23 | } 24 | } 25 | 26 | return maxJumps; 27 | } 28 | 29 | // O(N*N) & O(2*N) 30 | int solveWithMemo(vector& dp, vector& nums, int target, int start) { 31 | if(start == n-1) 32 | return 0; 33 | 34 | if(dp[start] != -1) 35 | return dp[start]; 36 | 37 | int maxJumps = INT_MIN; 38 | 39 | for(int jumpIdx = start+1; jumpIdx < n; ++jumpIdx) { 40 | int delta = nums[jumpIdx] - nums[start]; 41 | 42 | if(-target <= delta && delta <= target) { 43 | int nextJumps = solveWithMemo(dp, nums, target, jumpIdx); 44 | if(nextJumps != INT_MIN) { 45 | maxJumps = max(maxJumps, nextJumps + 1); 46 | } 47 | } 48 | } 49 | 50 | return dp[start] = maxJumps; 51 | } 52 | 53 | public: 54 | int maxJumpsToLastIndex(vector& nums, int target) { 55 | n = nums.size(); 56 | vector dp(n-1, -1); 57 | int maxJumps = solveWithMemo(dp, nums, target, 0); 58 | return (maxJumps == INT_MIN) ? -1 : maxJumps; 59 | } 60 | }; 61 | 62 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 63 | 64 | class BottomUp { 65 | public: 66 | // O(N*N) & O(1*N) 67 | int maxJumpsToLastIndex(vector& nums, int target) { 68 | int n = nums.size(); 69 | 70 | vector dp(n, -1); 71 | dp[n - 1] = 0; 72 | 73 | for(int start = n-2; start >= 0; --start) { 74 | int maxJumps = INT_MIN; 75 | 76 | for(int jumpIdx = start+1; jumpIdx < n; ++jumpIdx) { 77 | int delta = nums[jumpIdx] - nums[start]; 78 | 79 | if(-target <= delta && delta <= target) { 80 | int nextJumps = dp[jumpIdx]; 81 | if(nextJumps != INT_MIN) { 82 | maxJumps = max(maxJumps, nextJumps + 1); 83 | } 84 | } 85 | } 86 | 87 | dp[start] = maxJumps; 88 | } 89 | 90 | int maxJumps = dp[0]; 91 | return (maxJumps == INT_MIN) ? -1 : maxJumps; 92 | } 93 | }; 94 | 95 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 96 | 97 | Topics: Array | Dynamic Programming 98 | Link : https://leetcode.com/problems/maximum-number-of-jumps-to-reach-the-last-index/description/ 99 | -------------------------------------------------------------------------------- /Dynamic Programming/Tree DP/1 - House Robber III.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the maximum amount of money the thief can rob without alerting the police ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | // Class to implement the Top-down approach: 6 | class DynamicProgramming { 7 | public: 8 | // Method to find the maximum amount of money the thief can rob, using recursion with memoization - O(N) & O(N) 9 | int robMaxMoney(TreeNode* rootNode) { 10 | unordered_map memory; 11 | return solveWithMemo(rootNode, memory); 12 | } 13 | 14 | private: 15 | // O(2*N) & O(N+N) 16 | int solveWithMemo(TreeNode* rootNode, unordered_map& memory) { 17 | // Edge case: If there's no node then there's no money to rob 18 | if(!rootNode) 19 | return 0; 20 | 21 | // Memoization table: If the current state is already computed then return the computed value 22 | if(memory.count(rootNode)) 23 | return memory[rootNode]; 24 | 25 | // There are always two possibilities to perform at each node 26 | int currSkip = solveWithMemo(rootNode->left, memory) + solveWithMemo(rootNode->right, memory); // Is to skip it and move to it's child nodes 27 | int currRob = rootNode->val; // Is to rob it and take the value of it 28 | 29 | // If you rob the node then you can't rob at it's left child / adjacent node 30 | if(rootNode->left) 31 | currRob += solveWithMemo(rootNode->left->left, memory) + solveWithMemo(rootNode->left->right, memory); 32 | 33 | // If you rob the node then you can't rob at it's right child / adjacent node 34 | if(rootNode->right) 35 | currRob += solveWithMemo(rootNode->right->left, memory) + solveWithMemo(rootNode->right->right, memory); 36 | 37 | // Store the result value to the memoization table and then return it 38 | return memory[rootNode] = max(currRob, currSkip); 39 | } 40 | 41 | // O(2^N) & O(N) 42 | int solveWithoutMemo(TreeNode* rootNode) { 43 | // Edge case: If there's no node then there's no money to rob 44 | if(!rootNode) 45 | return 0; 46 | 47 | // There are always two possibilities to perform at each node 48 | int currSkip = solveWithoutMemo(rootNode->left) + solveWithoutMemo(rootNode->right); // Is to skip it and move to it's child nodes 49 | int currRob = rootNode->val; // Is to rob it and take the value of it 50 | 51 | // If you rob the node then you can't rob at it's left child / adjacent node 52 | if(rootNode->left) 53 | currRob += solveWithoutMemo(rootNode->left->left) + solveWithoutMemo(rootNode->left->right); 54 | 55 | // If you rob the node then you can't rob at it's right child / adjacent node 56 | if(rootNode->right) 57 | currRob += solveWithoutMemo(rootNode->right->left) + solveWithoutMemo(rootNode->right->right); 58 | 59 | // As we're striving for the maximum money hence return the maximum value 60 | return max(currRob, currSkip); 61 | } 62 | }; 63 | 64 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 65 | 66 | Topics: Dynamic Programming | Tree | Depth-First Search | Binary Tree 67 | Link : https://leetcode.com/problems/house-robber-iii/description/ 68 | -------------------------------------------------------------------------------- /Advanced/Tree/Fenwick Tree (BIT)/Range Sum Query - Immutable.cpp: -------------------------------------------------------------------------------- 1 | // Program to perform the "range sum queries" using "fenwick tree / binary indexed tree" ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class NumArray { 8 | private: 9 | vector& inputArray; 10 | int N; 11 | 12 | // O(N) Space for "BIT" array: Where N is the size of the "input array" 13 | vector BIT; 14 | 15 | // O(LogN) Time for each operation : Where N is the size of the "input array" 16 | void update(int index, int val) { 17 | while(index <= N) { 18 | BIT[index] += val; 19 | index += index & (-index); 20 | } 21 | } 22 | 23 | // O(LogN) Time for each operation : Where N is the size of the "input array" 24 | int getSum(int index) { 25 | int sum = 0; 26 | 27 | while(index) { 28 | sum += BIT[index]; 29 | index = index & (index-1); 30 | } 31 | 32 | return sum; 33 | } 34 | 35 | public: 36 | // O(NLogN) Time for "BIT" construction : Where N is the size of the "input array" 37 | NumArray(vector& nums) : inputArray(nums), N(nums.size()), BIT(nums.size()+1, 0) { 38 | for(int i=1; i<=N; ++i) { 39 | update(i, inputArray[i-1]); 40 | } 41 | } 42 | 43 | // O(KLogN) Time for all operations : Where K is the number of calls made to the "sumRange()" and N is the size of the "input array" 44 | int sumRange(int L, int R) { 45 | return getSum(R+1) - getSum(L); 46 | } 47 | }; 48 | 49 | // Driver code 50 | int main() { 51 | // Tracks the user wants to perform the operation or not 52 | bool userWantsOperation = true; 53 | 54 | while(userWantsOperation) { 55 | // Handles console clearance for both "windows" and "linux" user 56 | system("cls || clear"); 57 | 58 | // Input the size of the array 59 | int N; 60 | cout<<"Enter the size of the array: "; 61 | cin>>N; 62 | 63 | // Check the given size is valid or not 64 | if(N <= 0) { 65 | cout<<"Enter a valid size, application expects a positive integer!"; 66 | return 0; 67 | } 68 | 69 | // Stores the array values 70 | vector nums(N); 71 | 72 | // Input the array values 73 | cout<<"Enter the values of the array: "; 74 | for(int i=0; i>nums[i]; 76 | } 77 | 78 | // Input the range value 79 | int L, R; 80 | cout<<"\nEnter the range value (0-based indexing): "; 81 | cin>>L>>R; 82 | 83 | NumArray numArray = NumArray(nums); 84 | 85 | // Section to hit the range sum query 86 | if(L > -1 && R < N && L <= R && R >= L) { 87 | int rangeSum = numArray.sumRange(L, R); 88 | cout<<"The sum of range ["<>userChoise; 99 | userWantsOperation = (userChoise == 'Y' ? true : false); 100 | } 101 | 102 | return 0; 103 | } 104 | /* 105 | Topics: Array | Design | Binary Indexed Tree | Segment Tree 106 | Link: https://leetcode.com/problems/range-sum-query-immutable/description/ 107 | */ 108 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/15 - Geek Jump/Geek Jump.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum energy that can be used by the Geek to jump from step 0 to step N-1 ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(2^N) & O(N) 9 | int solveWithoutMemo(vector& heights, int idx) { 10 | if(idx == n-1) 11 | return 0; 12 | 13 | int jump1Step = abs(heights[idx + 1] - heights[idx]) + solveWithoutMemo(heights, idx + 1); 14 | int jump2Step = (idx + 2 < n) 15 | ? abs(heights[idx + 2] - heights[idx]) + solveWithoutMemo(heights, idx + 2) 16 | : INT_MAX; 17 | 18 | return min(jump1Step, jump2Step); 19 | } 20 | 21 | // O(2*N) & O(2*N) 22 | int solveWithMemo(vector& dp, vector& heights, int idx) { 23 | if(idx == n-1) 24 | return 0; 25 | 26 | if(dp[idx] != -1) 27 | return dp[idx]; 28 | 29 | int jump1Step = abs(heights[idx + 1] - heights[idx]) + solveWithMemo(dp, heights, idx + 1); 30 | int jump2Step = (idx + 2 < n) 31 | ? abs(heights[idx + 2] - heights[idx]) + solveWithMemo(dp, heights, idx + 2) 32 | : INT_MAX; 33 | 34 | return dp[idx] = min(jump1Step, jump2Step); 35 | } 36 | 37 | public: 38 | int minCostToReachTop(vector& heights) { 39 | n = heights.size(); 40 | vector dp(n-1, -1); 41 | return solveWithMemo(dp, heights, 0); 42 | } 43 | }; 44 | 45 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 46 | 47 | class BottomUp { 48 | int n; 49 | 50 | // O(1*N) & O(1*N) 51 | int solveWith1DTable(vector& heights) { 52 | vector dp(n, -1); 53 | dp[n - 1] = 0; 54 | 55 | for(int idx = n-2; idx >= 0; --idx) { 56 | int jump1Step = abs(heights[idx + 1] - heights[idx]) + dp[idx + 1]; 57 | int jump2Step = (idx + 2 < n) 58 | ? abs(heights[idx + 2] - heights[idx]) + dp[idx + 2] 59 | : INT_MAX; 60 | 61 | dp[idx] = min(jump1Step, jump2Step); 62 | } 63 | 64 | return dp[0]; 65 | } 66 | 67 | // O(1*N) & O(1) 68 | int solveWithoutTable(vector& heights) { 69 | int dp_idx_1 = 0; 70 | int dp_idx_2 = 0; 71 | int dp_idx = 0; 72 | 73 | for(int idx = n-2; idx >= 0; --idx) { 74 | int jump1Step = abs(heights[idx + 1] - heights[idx]) + dp_idx_1; 75 | int jump2Step = (idx + 2 < n) 76 | ? abs(heights[idx + 2] - heights[idx]) + dp_idx_2 77 | : INT_MAX; 78 | 79 | dp_idx = min(jump1Step, jump2Step); 80 | dp_idx_2 = dp_idx_1; 81 | dp_idx_1 = dp_idx; 82 | } 83 | 84 | return dp_idx; 85 | } 86 | 87 | public: 88 | int minCostToReachTop(vector& heights) { 89 | n = heights.size(); 90 | return solveWithoutTable(heights); 91 | } 92 | }; 93 | 94 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- 95 | 96 | Topics: Array | Dynamic Programming 97 | Links : https://www.geeksforgeeks.org/problems/geek-jump/1 98 | https://www.codingninjas.com/studio/problems/frog-jump_3621012 99 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/23 - Coin Change/23.2 - Coin Change (With Sorting).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the fewest number of coins that you need to make up the amount. If that amount of money cannot be made up by any combination of the coins then return -1. You may assume that you have an infinite number of each kind of coin ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N^A) & O(A) : Where A = amount 9 | int solveWithoutMemo(const vector& coins, int amount) { 10 | if(amount == 0) 11 | return 0; 12 | 13 | int minCoins = INT_MAX; 14 | 15 | for(int i = 0; (i < n && coins[i] <= amount); ++i) { 16 | int nextCoins = solveWithoutMemo(coins, amount - coins[i]); 17 | 18 | if(nextCoins != INT_MAX) { 19 | minCoins = min(minCoins, nextCoins + 1); 20 | } 21 | } 22 | 23 | return minCoins; 24 | } 25 | 26 | // O(N*A) & O(2*A) : Where A = amount 27 | int solveWithMemo(vector& dp, const vector& coins, int amount) { 28 | if(amount == 0) 29 | return 0; 30 | 31 | if(dp[amount] != -1) 32 | return dp[amount]; 33 | 34 | int minCoins = INT_MAX; 35 | 36 | for(int i = 0; (i < n && coins[i] <= amount); ++i) { 37 | int nextCoins = solveWithMemo(dp, coins, amount - coins[i]); 38 | 39 | if(nextCoins != INT_MAX) { 40 | minCoins = min(minCoins, nextCoins + 1); 41 | } 42 | } 43 | 44 | return dp[amount] = minCoins; 45 | } 46 | 47 | public: 48 | int minCoinsToMakeAmount(vector& coins, int amount) { 49 | n = coins.size(); 50 | sort(begin(coins), end(coins)); 51 | vector dp(amount + 1, -1); 52 | int minCoins = solveWithMemo(dp, coins, amount); 53 | return (minCoins == INT_MAX) ? -1 : minCoins; 54 | } 55 | }; 56 | 57 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 58 | 59 | class BottomUp { 60 | public: 61 | // O(A*N) & O(1*A) : Where A = givenAmount 62 | int minCoinsToMakeAmount(const vector& coins, int givenAmount) { 63 | int n = coins.size(); 64 | sort(begin(coins), end(coins)); 65 | 66 | vector dp(givenAmount + 1, -1); 67 | dp[0] = 0; 68 | 69 | for(int amount = 1; amount <= givenAmount; ++amount) { 70 | int minCoins = INT_MAX; 71 | 72 | for(int i = 0; (i < n && coins[i] <= amount); ++i) { 73 | int nextCoins = dp[amount - coins[i]]; 74 | 75 | if(nextCoins != INT_MAX) { 76 | minCoins = min(minCoins, nextCoins + 1); 77 | } 78 | } 79 | 80 | dp[amount] = minCoins; 81 | } 82 | 83 | int minCoins = dp[givenAmount]; 84 | return (minCoins == INT_MAX) ? -1 : minCoins; 85 | } 86 | }; 87 | 88 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 89 | 90 | Topics: Array | Dynamic Programming 91 | Links : https://leetcode.com/problems/coin-change/description/ 92 | https://cses.fi/problemset/task/1634 93 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/31 - Soup Servings.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the probability that A is used up before B plus half the probability that both soups are used up in the same turn ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 4 | 5 | class TopDown { 6 | const vector> operations = {{100, 0}, {75, 25}, {50, 50}, {25, 75}}; 7 | 8 | // O(4^(N+N)) & O(N+N) 9 | double solveWithoutMemo(int A, int B) { 10 | if(A <= 0 && B <= 0) 11 | return 0.5; // Half the probability of both the soups are used in same turn 12 | 13 | if(A <= 0) 14 | return 1.0; // Full probability of soup A is used before soup B 15 | 16 | if(B <= 0) 17 | return 0.0; 18 | 19 | double prob = 0.0; 20 | 21 | for(const auto& op : operations) { 22 | int newA = A - op[0]; 23 | int newB = B - op[1]; 24 | prob += solveWithoutMemo(newA, newB); 25 | } 26 | 27 | return 0.25 * prob; 28 | } 29 | 30 | // O(4*N*N) & O(N*N + N+N) 31 | double solveWithMemo(vector>& dp, int A, int B) { 32 | if(A <= 0 && B <= 0) 33 | return 0.5; // Half the probability of both the soups are used in same turn 34 | 35 | if(A <= 0) 36 | return 1.0; // Full probability of soup A is used before soup B 37 | 38 | if(B <= 0) 39 | return 0.0; 40 | 41 | if(dp[A][B] != -1.0) 42 | return dp[A][B]; 43 | 44 | double prob = 0.0; 45 | 46 | for(const auto& op : operations) { 47 | int newA = A - op[0]; 48 | int newB = B - op[1]; 49 | prob += solveWithMemo(dp, newA, newB); 50 | } 51 | 52 | return dp[A][B] = 0.25 * prob; 53 | } 54 | 55 | public: 56 | // Method to find specified probability, using recursion with memoization - O(N^2) & O(N^2) 57 | double soupServings(int n) { 58 | if(n >= 6000) 59 | return 1.0; 60 | vector> dp(n + 1, vector(n + 1, -1.0)); 61 | return solveWithMemo(dp, n, n); 62 | } 63 | }; 64 | 65 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 66 | 67 | class BottomUp { 68 | const vector> operations = {{100, 0}, {75, 25}, {50, 50}, {25, 75}}; 69 | 70 | public: 71 | // O(N^2) & O(N^2) 72 | double soupServings(int n) { 73 | if(n >= 6000) 74 | return 1.0; 75 | 76 | vector> dp(n + 1, vector(n + 1, -1.0)); 77 | 78 | for(int A = 0; A <= n; ++A) { 79 | for(int B = 0; B <= n; ++B) { 80 | double prob = 0.0; 81 | 82 | for(const auto& op : operations) { 83 | int newA = A - op[0]; 84 | int newB = B - op[1]; 85 | if(newA <= 0 && newB <= 0) prob += 0.5; 86 | else if(newA <= 0) prob += 1.0; 87 | else if(newB <= 0) prob += 0.0; 88 | else prob += dp[newA][newB]; 89 | } 90 | 91 | dp[A][B] = 0.25 * prob; 92 | } 93 | } 94 | 95 | return dp[n][n]; 96 | } 97 | }; 98 | 99 | ------------------------------------------------------------------------------------------------------------------------------------------------------ 100 | 101 | Topics: Math | Dynamic Programming | Probability and Statistics | Weekly Contest 78 102 | Link : https://leetcode.com/problems/soup-servings/description/ 103 | -------------------------------------------------------------------------------- /Dynamic Programming/Graph DP/2 - Parallel Courses III.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum number of months needed to complete all the courses such that by following the mentioned rules ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | // Class to implement the Top-down approach: 6 | class DynamicProgramming { 7 | vector> adjList; 8 | vector visited; 9 | 10 | // O(N * M^N) & O(N) 11 | int solveWithoutMemo(int course, vector& time) { 12 | // Stores the total time required to complete the course 13 | int maximumTime = 0; 14 | 15 | // Explore each neighbour courses and find the maximum remaining time to complete the course 16 | for(int neighbor : adjList[course]) 17 | maximumTime = max(maximumTime, solveWithoutMemo(neighbor, time)); 18 | 19 | // Return the result value 20 | return (maximumTime == 0) ? time[course - 1] : time[course - 1] + maximumTime; 21 | } 22 | 23 | // O(N + M*N) & O(N+N) 24 | int solveWithMemo(int course, vector& time) { 25 | // Stores the total time required to complete the course 26 | int maximumTime = 0; 27 | 28 | for(int neighbor : adjList[course]) { 29 | // If the current state is not computed then find the maximum remaining time to complete the course 30 | if(!visited[neighbor]) { 31 | maximumTime = max(maximumTime, solveWithMemo(neighbor, time)); 32 | } 33 | // If the current state is already computed then update the result by the maximum value 34 | else { 35 | maximumTime = max(maximumTime, visited[neighbor]); 36 | } 37 | } 38 | 39 | // Store the result value to the memoization table and then return it 40 | return visited[course] = (maximumTime == 0) ? time[course - 1] : time[course - 1] + maximumTime; 41 | } 42 | 43 | public: 44 | // Method to find minimum number of months needed to complete all the courses, using recursion with memoization - O(M*N) & O(N) : Where M let be the maxmium number of neighbours of any course 45 | int minimumTime(int n, vector>& relations, vector& time) { 46 | // Edge case: If there are no relations then return the maximum time 47 | if(relations.size() == 0) 48 | return *max_element(begin(time), end(time)); 49 | 50 | adjList.resize(n + 1); // Stores the list of neighbour courses of each course 51 | visited.resize(n + 1); // Memoization table 52 | 53 | // Create the adjacency list 54 | for(auto& r : relations) { 55 | int prevCourse = r[1]; 56 | int nextCourse = r[0]; 57 | adjList[prevCourse].push_back(nextCourse); 58 | } 59 | 60 | // Stores the result value 61 | int minMonths = 0; 62 | 63 | // Start doing the courses and find the total time required to complete all the courses through each of them and update the result by the maximum value 64 | for(int course = 1; course <= n; ++course) 65 | if(!visited[course]) 66 | minMonths = max(minMonths, solveWithMemo(course, time)); 67 | 68 | // Return the result value 69 | return minMonths; 70 | } 71 | }; 72 | 73 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 74 | 75 | Topics: Array | Dynamic Programming | Graph | Topological Sort 76 | Link : https://leetcode.com/problems/parallel-courses-iii/description/ 77 | -------------------------------------------------------------------------------- /Array/Rearrange Array Elements By Sign.cpp: -------------------------------------------------------------------------------- 1 | // Program to return the modified array after rearranging the elements to satisfy the aforementioned conditions ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | 6 | // Solution class: 7 | class Solution { 8 | public: 9 | // #1 Method to rearrange the elements as mentioned, using multiple buffers - O(N) & O(N) 10 | std::vector rearrangeArray_V1(std::vector& nums) { 11 | int n = nums.size(); 12 | 13 | std::vector posNumbers; // Stores the positive values of the array 14 | std::vector negNumbers; // Stores the negative values of the array 15 | 16 | // Iterate the array and store the values 17 | for(int num : nums) 18 | (num > 0) ? posNumbers.push_back(num) : negNumbers.push_back(num); 19 | 20 | int i = 0; 21 | 22 | // Iterate and store the positive values at the even index 23 | for(int num : posNumbers) 24 | nums[i] = num, i += 2; 25 | 26 | i = 1; 27 | 28 | // Iterate and store the negative values at the odd index 29 | for(int num : negNumbers) 30 | nums[i] = num, i += 2; 31 | 32 | // Return the "modified array / result array" 33 | return nums; 34 | } 35 | 36 | // #2 Method to rearrange the elements as mentioned, using single buffer - O(N) & O(N) 37 | std::vector rearrangeArray_V2(std::vector& nums) { 38 | int n = nums.size(); 39 | int i = 0, j = 1; 40 | 41 | // Stores the result values 42 | std::vector output(n, 0); 43 | 44 | // Iterate the array 45 | for(int num : nums) { 46 | // Store the positive value at the even index of the "output array" 47 | (num > 0) ? output[i] = num, i += 2 : 0; 48 | // Store the negative value at the odd index of the "output array" 49 | (num < 0) ? output[j] = num, j += 2 : 0; 50 | } 51 | 52 | // Return the "output array" 53 | return output; 54 | } 55 | }; 56 | 57 | // Driver code 58 | int main() { 59 | // Tracks the user wants to perform the operation or not 60 | bool userWantsOperation = true; 61 | 62 | while(userWantsOperation) { 63 | // Handles console clearance for both "windows" and "linux" user 64 | system("cls || clear"); 65 | 66 | // Input the size of the array 67 | int size; 68 | std::cout<<"Enter size of the array: "; 69 | std::cin>>size; 70 | 71 | // Check the given size is valid or not 72 | if(size <= 0) { 73 | std::cout<<"Enter a valid size, applicatin expects a positive integer!"; 74 | return 0; 75 | } 76 | 77 | // Stores the array values 78 | std::vector nums(size, 0); 79 | 80 | // Input the array values 81 | std::cout<<"Enter values of the array: "; 82 | for(int i=0; i>nums[i]; 84 | 85 | // Rearrangement call 86 | Solution obj; 87 | nums = obj.rearrangeArray_V2(nums); 88 | 89 | // Print values 90 | std::cout<<"Result array: "; 91 | for(int num : nums) 92 | std::cout<>userChoice; 98 | userWantsOperation = (userChoice == 'R' ? true : false); 99 | } 100 | 101 | return 0; 102 | } 103 | /* 104 | Topics: Array | Two Pointers | Simulation 105 | Link: https://leetcode.com/problems/rearrange-array-elements-by-sign/description/ 106 | */ 107 | -------------------------------------------------------------------------------- /Bit Manipulation/Check If Bitwise OR Has Trailing Zeros.cpp: -------------------------------------------------------------------------------- 1 | // Program to check if it is possible to select two or more elements whose bitwise OR has trailing zeros or not ~ coded by Hiren 2 | #include 3 | #define loop(i,n,k) for(int i=(k?k:0); i& nums) { 12 | int n = nums.size(); 13 | 14 | loop(i, n, 0) 15 | loop(j, n, i+1) 16 | // Its observed that the "even elements" always contain trailing zero, hence check for the trailing zeros by OR operation 17 | if((nums[i] | nums[j]) % 2 == 0) 18 | return true; 19 | 20 | // Return false, if reached here 21 | return false; 22 | } 23 | 24 | // #2 Method to check if bitwise OR has trailing zeros or not, using constant auxiliary space - O(N) & O(1) 25 | bool hasTrailingZeros_V2(vector& nums) { 26 | int n = nums.size(); 27 | 28 | // Stores any "even element" with its index 29 | int evenNum = -1, evenNumIdx = -1; 30 | 31 | // Iterate the array 32 | loop(i, n, 0) { 33 | // If the ith element is "even" then mark the element with its index 34 | if(even(nums[i])) { 35 | evenNum = nums[i], evenNumIdx = i; 36 | break; 37 | } 38 | } 39 | 40 | // Iterate the array and look for an another "even element" 41 | loop(i, n, 0) { 42 | // If the ith element is "even" and its at unique index then check for the trailing zeros by OR operation 43 | if((i != evenNumIdx) && (even(nums[i])) && (evenNum | nums[i]) % 2 == 0) { 44 | return true; 45 | } 46 | } 47 | 48 | // Return false, if reached here 49 | return false; 50 | } 51 | }; 52 | 53 | // Driver code 54 | int main() { 55 | // Tracks for the user wants to perform the operation or not 56 | bool canPerformOperation = true; 57 | 58 | while(canPerformOperation) { 59 | // Handles console clearance for both "windows" and "linux" user 60 | system("cls || clear"); 61 | 62 | // Input section for the size of the array 63 | cout<<"Enter the size of the array: "; 64 | int n; cin>>n; 65 | 66 | // Check for the given size is valid or not 67 | if(n <= 0) { 68 | cout<<"Enter a valid size, application expects a positive integer!"; 69 | return 0; 70 | } 71 | 72 | vector nums(n); 73 | 74 | cout<<"Enter the array elements: "; 75 | 76 | // Input section for the array elements 77 | for(int i=0; i>nums[i]; 79 | } 80 | 81 | // Verification call 82 | Solution solution; 83 | if(solution.hasTrailingZeros_V2(nums)) 84 | cout<<"Its possible to select two or more elements whose bitwise OR has trailing zeros!"; 85 | else 86 | cout<<"Its not possible to select two or more elements whose bitwise OR has trailing zeros!"; 87 | 88 | // Input section to handle the flow of iterations of the application 89 | char userChoise; 90 | cout<<"\n\nPress \'R\' to restart the application, else application will exit automatically: "; 91 | cin>>userChoise; 92 | canPerformOperation = (userChoise == 'R'); 93 | } 94 | 95 | return 0; 96 | } 97 | /* 98 | Topics: Array | Bit Manipulation 99 | Link: https://leetcode.com/problems/check-if-bitwise-or-has-trailing-zeros/ 100 | */ 101 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/14 - Minimum Cost For Tickets/14.1 - Minimum Cost For Tickets (Linear Search).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum number of dollars you need to travel every day in the given list of days ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | int getNextStartDay(vector& days, int target, int start) { 9 | for(int idx = start; idx < n; ++idx) 10 | if(days[idx] >= target) 11 | return idx; 12 | return n; 13 | } 14 | 15 | // O(3^N * N) & O(N) 16 | int solveWithoutMemo(vector& days, vector& costs, int idx) { 17 | if(idx == n) 18 | return 0; 19 | 20 | // There are three possibilities to perform at each day 21 | int oneDayPass = costs[0] + solveWithoutMemo(days, costs, getNextStartDay(days, days[idx] + 1, idx + 1)); // To buy 1-day pass 22 | int sevenDayPass = costs[1] + solveWithoutMemo(days, costs, getNextStartDay(days, days[idx] + 7, idx + 1)); // To buy 7-day pass 23 | int thirtyDayPass = costs[2] + solveWithoutMemo(days, costs, getNextStartDay(days, days[idx] + 30, idx + 1)); // To buy 30-day pass 24 | 25 | return min({oneDayPass, sevenDayPass, thirtyDayPass}); 26 | } 27 | 28 | // O(3*N*N) & O(2*N) 29 | int solveWithMemo(vector& dp, vector& days, vector& costs, int idx) { 30 | if(idx == n) 31 | return 0; 32 | 33 | if(dp[idx] != -1) 34 | return dp[idx]; 35 | 36 | // There are three possibilities to perform at each day 37 | int oneDayPass = costs[0] + solveWithMemo(dp, days, costs, getNextStartDay(days, days[idx] + 1, idx + 1)); // To buy 1-day pass 38 | int sevenDayPass = costs[1] + solveWithMemo(dp, days, costs, getNextStartDay(days, days[idx] + 7, idx + 1)); // To buy 7-day pass 39 | int thirtyDayPass = costs[2] + solveWithMemo(dp, days, costs, getNextStartDay(days, days[idx] + 30, idx + 1)); // To buy 30-day pass 40 | 41 | return dp[idx] = min({oneDayPass, sevenDayPass, thirtyDayPass}); 42 | } 43 | 44 | public: 45 | int mincostTickets(vector& days, vector& costs) { 46 | n = days.size(); 47 | vector dp(n, -1); 48 | return solveWithMemo(dp, days, costs, 0); 49 | } 50 | }; 51 | 52 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 53 | 54 | class BottomUp { 55 | int n; 56 | 57 | int getNextStartDay(vector& days, int target, int start) { 58 | for(int idx = start; idx < n; ++idx) 59 | if(days[idx] >= target) 60 | return idx; 61 | return n; 62 | } 63 | 64 | public: 65 | // O(N*N) & O(N) 66 | int mincostTickets(vector& days, vector& costs) { 67 | n = days.size(); 68 | 69 | vector dp(n + 1, -1); 70 | dp[n] = 0; 71 | 72 | for(int idx = n-1; idx >= 0; --idx) { 73 | int oneDayPass = costs[0] + dp[getNextStartDay(days, days[idx] + 1, idx + 1)]; 74 | int sevenDayPass = costs[1] + dp[getNextStartDay(days, days[idx] + 7, idx + 1)]; 75 | int thirtyDayPass = costs[2] + dp[getNextStartDay(days, days[idx] + 30, idx + 1)]; 76 | dp[idx] = min({oneDayPass, sevenDayPass, thirtyDayPass}); 77 | } 78 | 79 | return dp[0]; 80 | } 81 | }; 82 | 83 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 84 | 85 | Topics: Array | Binary Search | Dynamic Programming 86 | Link : https://leetcode.com/problems/minimum-cost-for-tickets/description/ 87 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/15 - nCr.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the nCr of given two integers ~ coded by Hiren 2 | 3 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | // O(2^(N*R)) & O(N) 7 | int solveWithoutMemo(int R, int C) { 8 | if(C == 0 || C == R) 9 | return 1; 10 | 11 | int moveUp = solveWithoutMemo(R-1, C); 12 | int moveUpPrev = solveWithoutMemo(R-1, C-1); 13 | 14 | return moveUp + moveUpPrev; 15 | } 16 | 17 | // O(2*N*R) & O(N*R + N) 18 | int solveWithMemo(vector>& dp, int R, int C) { 19 | if(C == 0 || C == R) 20 | return 1; 21 | 22 | if(dp[R][C] != -1) 23 | return dp[R][C]; 24 | 25 | int moveUp = solveWithMemo(dp, R-1, C); 26 | int moveUpPrev = solveWithMemo(dp, R-1, C-1); 27 | 28 | return dp[R][C] = moveUp + moveUpPrev; 29 | } 30 | 31 | public: 32 | // Method to find value of nCr, using recursion with memoization - O(N*R) & O(N*R) 33 | int nCr(int N, int R) { 34 | if(R > N) 35 | return 0; 36 | vector> dp(N+1, vector(R+1, -1)); 37 | return solveWithMemo(dp, N, R); // To find nCr, just find the value of pascal[N][R], where (N,R) are 0-based indexing and pascal represents the 2D array storing values of pascal triangle 38 | } 39 | }; 40 | 41 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 42 | 43 | class BottomUp { 44 | // O(N*N) & O(N*N) : Where N = given_N 45 | int solveWith2DTable(int given_N, int given_R) { 46 | vector> dp(given_N+1, vector(given_N+1, -1)); 47 | 48 | for(int R = 0; R <= given_N; ++R) 49 | dp[R][0] = dp[R][R] = 1; 50 | 51 | for(int R = 1; R <= given_N; ++R) { 52 | for(int C = 1; C < R; ++C) { 53 | int moveUp = dp[R-1][C]; 54 | int moveUpPrev = dp[R-1][C-1]; 55 | dp[R][C] = moveUp + moveUpPrev; 56 | } 57 | } 58 | 59 | return dp[given_N][given_R]; 60 | } 61 | 62 | // O(N*N) & O(2*N) : Where N = given_N 63 | int solveWith1DTable(int given_N, int given_R) { 64 | vector prevRow(given_N, 1); 65 | // prevRow[0] = 1; // If yow want array like this: vector prevRow(N, -1); then uncomment this line 66 | 67 | for(int R = 1; R <= given_N; ++R) { 68 | vector currRow(R+1, 1); // Setting to 1 also initializes the base case, but if you want array like: vector currRow(R+1, -1); then do this: currRow[0] = currRow[R] = 1; 69 | for(int C = 1; C < R; ++C) { 70 | int moveUp = prevRow[C]; 71 | int moveUpPrev = prevRow[C-1]; 72 | currRow[C] = moveUp + moveUpPrev; 73 | } 74 | prevRow = currRow; 75 | } 76 | 77 | return prevRow[given_R]; 78 | } 79 | 80 | public: 81 | int nCr(int N, int R) { 82 | if(R > N) 83 | return 0; 84 | return solveWith1DTable(N, R); 85 | } 86 | }; 87 | 88 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 89 | 90 | Topics: Array | Dynamic Programming 91 | Links : https://www.geeksforgeeks.org/problems/ncr1019/1 92 | https://github.com/hiren-j/dsaAffection/blob/C%2B%2B/Dynamic%20Programming/Multi%20Dimensional%20DP/Pascal's%20Triangle%20II.cpp 93 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/16 - Geek Jump With K Steps/Geek Jump With K Steps.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum possible total cost incurred before the Geek reaches the nth stone, the Geek can jump to any one of the following, stone + 1, stone + 2, ... stone + K stone and cost will be [hi - hj] is incurred, where jump is the stone to land on ~ coded by Hiren 2 | 3 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(K^N) & O(N) 9 | int solveWithoutMemo(const vector& nums, const int k, int index) { 10 | if(index == n-1) 11 | return 0; // If reached last stone, return 0 as indication 12 | 13 | int minCost = INT_MAX; 14 | 15 | for(int jump = 1; (jump <= k && index + jump < n); ++jump) { // Try each possible jump from the index 16 | int jumpCost = abs(nums[index + jump] - nums[index]); 17 | int nextCost = solveWithoutMemo(nums, k, index + jump); 18 | int currPathCost = jumpCost + nextCost; 19 | minCost = min(minCost, currPathCost); 20 | } 21 | 22 | return minCost; 23 | } 24 | 25 | // O(K*N) & O(2*N) 26 | int solveWithMemo(vector& dp, const vector& nums, const int k, int index) { 27 | if(index == n-1) 28 | return 0; // If reached last stone, return 0 as indication 29 | 30 | if(dp[index] != -1) 31 | return dp[index]; 32 | 33 | int minCost = INT_MAX; 34 | 35 | for(int jump = 1; (jump <= k && index + jump < n); ++jump) { // Try each possible jump from the index 36 | int jumpCost = abs(nums[index + jump] - nums[index]); 37 | int nextCost = solveWithMemo(dp, nums, k, index + jump); 38 | int currPathCost = jumpCost + nextCost; 39 | minCost = min(minCost, currPathCost); 40 | } 41 | 42 | return dp[index] = minCost; 43 | } 44 | 45 | public: 46 | int minimizeCost(int k, vector& nums) { 47 | n = nums.size(); 48 | vector dp(n-1, -1); 49 | return solveWithMemo(dp, nums, k, 0); 50 | } 51 | }; 52 | 53 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 54 | 55 | class BottomUp { 56 | public: 57 | // O(N*K) & O(N) 58 | int minimizeCost(const int k, const vector& nums) { 59 | int n = nums.size(); 60 | 61 | vector dp(n, -1); 62 | dp[n - 1] = 0; // Initialize edge case 63 | 64 | for(int index = n-2; index >= 0; --index) { 65 | int minCost = INT_MAX; 66 | 67 | for(int jump = 1; (jump <= k && index + jump < n); ++jump) { 68 | int jumpCost = abs(nums[index + jump] - nums[index]); 69 | int nextCost = dp[index + jump]; 70 | int currPathCost = jumpCost + nextCost; 71 | minCost = min(minCost, currPathCost); 72 | } 73 | 74 | dp[index] = minCost; 75 | } 76 | 77 | return dp[0]; 78 | } 79 | }; 80 | 81 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 82 | 83 | Topics: Array | Dynamic Programming 84 | Link : https://www.geeksforgeeks.org/problems/minimal-cost/1 85 | -------------------------------------------------------------------------------- /Dynamic Programming/LIS DP/5 - Largest Divisible Subset.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the largest subset answer such that every pair (answer[i], answer[j]) of elements in this subset satisfies: answer[i] % answer[j] == 0, or answer[j] % answer[i] == 0 ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class BottomUp { 6 | // O(N^2) & O(N^2) 7 | vector solveBy2DTable(vector& nums) { 8 | sort(begin(nums), end(nums)); 9 | int n = nums.size(); 10 | int maxLenLDS = 0; 11 | 12 | vector LDS(n, 1); // LDS[i] represents the length of the LDS ending at that ith index 13 | vector> divSubset(n); // divSubset[i] stores the values of the longest divisible subset ending at that ith index 14 | 15 | for(int j = 0; j < n; ++j) { // Find the length of longest divisible subset and the values of it 16 | divSubset[j].push_back(nums[j]); 17 | for(int i = 0; i < j; ++i) { 18 | if(nums[j] % nums[i] == 0) { 19 | if(LDS[j] < LDS[i] + 1) { 20 | LDS[j] = LDS[i] + 1; 21 | divSubset[j] = divSubset[i]; 22 | divSubset[j].push_back(nums[j]); 23 | } 24 | } 25 | } 26 | maxLenLDS = max(maxLenLDS, LDS[j]); 27 | } 28 | 29 | for(int j = 0; j < n; ++j) // Return the values of the longest divisible subset 30 | if(LDS[j] == maxLenLDS) 31 | return divSubset[j]; 32 | 33 | return {}; 34 | } 35 | 36 | // O(N^2) & O(N) 37 | vector solveBy1DTable(vector& nums) { 38 | int n = nums.size(); 39 | sort(begin(nums), end(nums)); 40 | 41 | vector LDS(n, 1); // LDS[i] represents the length of the LDS ending at that ith index 42 | vector temp(n, -1); // temp[i] represents the index of the recently seen value which is considered as the part of the LDS ending at that ith index 43 | 44 | // Find the length of the (LDS) longest divisible subset ending at index i 45 | for(int i = 0; i < n; ++i) { 46 | temp[i] = i; 47 | for(int j = 0; j < i; ++j) { 48 | if(nums[i] % nums[j] == 0) { 49 | if(1 + LDS[j] > LDS[i]) { 50 | LDS[i] = 1 + LDS[j]; 51 | temp[i] = j; 52 | } 53 | } 54 | } 55 | } 56 | 57 | int maxLenLDS = -1; 58 | int maxLenIdx = -1; 59 | 60 | for(int i = 0; i < n; ++i) { // Find the length of the longest divisible subset 61 | if(LDS[i] > maxLenLDS) { 62 | maxLenLDS = LDS[i]; 63 | maxLenIdx = i; 64 | } 65 | } 66 | 67 | vector LDS; 68 | while(maxLenIdx != temp[maxLenIdx]) { // Store the result values 69 | LDS.push_back(nums[maxLenIdx]); 70 | maxLenIdx = temp[maxLenIdx]; 71 | } 72 | LDS.push_back(nums[maxLenIdx]); 73 | 74 | reverse(begin(LDS), end(LDS)); // Reverse the result array to get the actual order 75 | return LDS; 76 | } 77 | 78 | public: 79 | // Method to find the largest divisible subset, using tabulation :- 80 | vector largestDivisibleSubset(vector& nums) { 81 | return solveBy1DTable(nums); 82 | } 83 | }; 84 | 85 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 86 | 87 | Topics: Array | Dynamic Programming 88 | Link : https://leetcode.com/problems/largest-divisible-subset/description/ 89 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/2 - Filling Bucket/Filling Bucket.cpp: -------------------------------------------------------------------------------- 1 | // Code to find in how many ways we could fill the given bucket. Given a Bucket having a capacity of N litres and the task is to determine that by how many ways you can fill it using two bottles of capacity of 1 Litre and 2 Litre only. Find the answer using modulo 1e8 ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | const int MOD = 1e8; 7 | 8 | // O(2^N) & O(N) 9 | int solveWithoutMemo(int N) { 10 | if(N == 0) // Edge case: If you've filled the whole bucket then you've 1 way 11 | return 1; 12 | 13 | if(N < 0) // Edge case: If the bucket is overfilled then its not valid 14 | return 0; 15 | 16 | // There are always two possibilities to perform 17 | int fill1Litre = solveWithoutMemo(N - 1); // Is to fill bucket with 1 litre 18 | int fill2Litre = solveWithoutMemo(N - 2); // Is to fill bucket with 2 litre 19 | 20 | return (fill1Litre + fill2Litre) % MOD; 21 | } 22 | 23 | // O(2*N) & O(2*N) 24 | int solveWithMemo(vector& dp, int N) { 25 | if(N == 0) // Edge case: If you've filled the whole bucket then you've 1 way 26 | return 1; 27 | 28 | if(N < 0) // Edge case: If the bucket is overfilled then its not valid 29 | return 0; 30 | 31 | if(dp[N] != -1) 32 | return dp[N]; 33 | 34 | // There are always two possibilities to perform 35 | int fill1Litre = solveWithMemo(dp, N - 1); // Is to fill bucket with 1 litre 36 | int fill2Litre = solveWithMemo(dp, N - 2); // Is to fill bucket with 2 litre 37 | 38 | return dp[N] = (fill1Litre + fill2Litre) % MOD; 39 | } 40 | 41 | public: 42 | int numWaysToFillBucket(int N) { 43 | vector dp(N + 1, -1); 44 | return solveWithMemo(dp, N); 45 | } 46 | }; 47 | 48 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 49 | 50 | class BottomUp { 51 | const int MOD = 1e8; 52 | 53 | // O(1*N) & O(1*N) 54 | int solveWith1DTable(int N) { 55 | vector dp(N + 1, -1); 56 | dp[0] = 1; // Init the first edge case 57 | 58 | for(int capacity = 1; capacity <= N; ++capacity) { 59 | int fill1Litre = dp[capacity - 1]; 60 | int fill2Litre = (capacity - 2 >= 0) ? dp[capacity - 2] : 0; 61 | dp[capacity] = (fill1Litre + fill2Litre) % MOD; 62 | } 63 | 64 | return dp[N]; 65 | } 66 | 67 | // O(1*N) & O(1) 68 | int solveWithoutTable(int N) { 69 | int fill1Litre = 1; // Init the first edge case 70 | int fill2Litre = 0; 71 | int numWays = 0; 72 | 73 | for(int capacity = 1; capacity <= N; ++capacity) { 74 | numWays = (fill1Litre + fill2Litre) % MOD; 75 | fill2Litre = fill1Litre; 76 | fill1Litre = numWays; 77 | } 78 | 79 | return numWays; 80 | } 81 | 82 | public: 83 | int numWaysToFillBucket(int N) { 84 | return solveWithoutTable(N); 85 | } 86 | }; 87 | 88 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 89 | 90 | Topics: Array | Dynamic Programming 91 | Link : https://www.geeksforgeeks.org/problems/filling-bucket0529/0 92 | -------------------------------------------------------------------------------- /Backtracking/Power Set.cpp: -------------------------------------------------------------------------------- 1 | // Program to find all the possible subsequences of the string "s" in lexicographically-sorted order ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // #1 Backtracking approach: 9 | class Backtracking_V1 { 10 | vector allSubsequences; 11 | 12 | void getAllUniqueSubsequences(const string& s, string& currSubsequence, int n, int i) { 13 | if(i >= n) { 14 | if(currSubsequence != "") { 15 | allSubsequences.push_back(currSubsequence); 16 | } 17 | return; 18 | } 19 | 20 | // Include the element and move one 21 | currSubsequence.push_back(s[i]); 22 | getAllUniqueSubsequences(s, currSubsequence, n, i+1); 23 | currSubsequence.pop_back(); 24 | 25 | // Exclude the element and move one 26 | getAllUniqueSubsequences(s, currSubsequence, n, i+1); 27 | } 28 | 29 | public: 30 | // Method to find all the possible subsequences of the string "s" in lexicographically-sorted order - O(2^N * N) & O(2^N * N) 31 | vector AllPossibleStrings(const string& s) { 32 | string currSubsequence; 33 | getAllUniqueSubsequences(s, currSubsequence, s.size(), 0); 34 | sort(begin(allSubsequences), end(allSubsequences)); 35 | return allSubsequences; 36 | } 37 | }; 38 | 39 | // #2 Backtracking approach: 40 | class Backtracking_V2 { 41 | vector allSubsequences; 42 | 43 | void getAllUniqueSubsequences(const string& s, string& currSubsequence, int n, int startIdx) { 44 | if(currSubsequence != "") 45 | allSubsequences.push_back(currSubsequence); 46 | 47 | for(int i=startIdx; i AllPossibleStrings(const string& s) { 57 | string currSubsequence; 58 | getAllUniqueSubsequences(s, currSubsequence, s.size(), 0); 59 | sort(begin(allSubsequences), end(allSubsequences)); 60 | return allSubsequences; 61 | } 62 | }; 63 | 64 | // Driver code 65 | int main() { 66 | // Tracks the user wants to perform the operation or not 67 | bool userWantsOperation = true; 68 | 69 | while(userWantsOperation) { 70 | // Controls console clearance for both "windows" and "linux" user 71 | system("cls || clear"); 72 | 73 | // Input a string 74 | string s; 75 | cout<<"Enter a string: "; 76 | cin>>s; 77 | 78 | // Call to get the list containing all the possible subsequences of the string "s" 79 | Backtracking_V2 bt; 80 | vector allSubsequences = bt.AllPossibleStrings(s); 81 | 82 | // Print each subsequence of the string "s" 83 | cout<<"\nList of all the possible subsequences in lexicographically-sorted order:\n"; 84 | for(auto& currSubsequence: allSubsequences) { 85 | int size = currSubsequence.size(); 86 | cout<<"["; 87 | for(int i=0; i>userChoice; 97 | userWantsOperation = (userChoice == 'R' ? true : false); 98 | } 99 | 100 | return 0; 101 | } 102 | /* 103 | Topics: String | Backtracking 104 | Link: https://www.geeksforgeeks.org/problems/power-set4302/1 105 | */ 106 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/30 - Ways To Express an Integer as Sum of Powers.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the number of ways n can be expressed as the sum of the xth power of unique positive integers ~ coded by Hiren 2 | 3 | ----------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | /* 6 | DON'T FORGET, REGARDING INTUITION BEHIND THE PRECOMPUTATION OF POWERS: 7 | : xthPower[i] represents pow(i, x) where i <= n. 8 | : Brute forcely we could use pow(i, x) but this will lead to TLE, due to log(x) more increament in time. 9 | : So It would be beneficial to precomute the xth power of every possible number (i <= n). 10 | */ 11 | 12 | ----------------------------------------------------------------------------------------------------------------------------------------------------- 13 | 14 | class TopDown { 15 | const int MOD = 1e9 + 7; 16 | vector xthPower; 17 | 18 | void precomputeXthPower(int n, int x) { 19 | xthPower.resize(n + 1); 20 | 21 | for(int i = 1; i <= n; ++i) { 22 | xthPower[i] = (long long)pow(i, x); 23 | } 24 | } 25 | 26 | // O(N^N) & O(2*N) 27 | int solveWithoutMemo(int n, int start, int x) { 28 | if(n == 0) 29 | return 1; 30 | 31 | int count = 0; 32 | 33 | for(int i = start; (i <= n && xthPower[i] <= n); ++i) { 34 | count = (count + solveWithoutMemo(n - xthPower[i], i + 1, x)) % MOD; 35 | } 36 | 37 | return count; 38 | } 39 | 40 | // O(N*N*N) & O(N*N + 2*N) 41 | int solveWithMemo(vector>& dp, int n, int start, int x) { 42 | if(n == 0) 43 | return 1; 44 | 45 | if(dp[n][start] != -1) 46 | return dp[n][start]; 47 | 48 | int count = 0; 49 | 50 | for(int i = start; (i <= n && xthPower[i] <= n); ++i) { 51 | count = (count + solveWithMemo(dp, n - xthPower[i], i + 1, x)) % MOD; 52 | } 53 | 54 | return dp[n][start] = count; 55 | } 56 | 57 | public: 58 | // Method to find number of ways, using recursion with memoization - O(N^3) & O(N^2) 59 | int numberOfWays(int n, int x) { 60 | precomputeXthPower(n, x); 61 | vector> dp(n + 1, vector(n + 1, -1)); 62 | return solveWithMemo(dp, n, 1, x); 63 | } 64 | }; 65 | 66 | ----------------------------------------------------------------------------------------------------------------------------------------------------- 67 | 68 | class BottomUp { 69 | const int MOD = 1e9 + 7; 70 | vector xthPower; 71 | 72 | void precomputeXthPower(int n, int x) { 73 | xthPower.resize(n + 1); 74 | 75 | for(int i = 1; i <= n; ++i) { 76 | xthPower[i] = (long long)pow(i, x); 77 | } 78 | } 79 | 80 | // O(N^3) & O(N^2) 81 | int solveWith2DTable(int n, int x) { 82 | vector> dp(n + 1, vector(n + 2, 0)); 83 | 84 | for(int start = 0; start <= n + 1; ++start) 85 | dp[0][start] = 1; 86 | 87 | for(int num = 1; num <= n; ++num) { 88 | for(int start = n; start >= 1; --start) { 89 | int count = 0; 90 | 91 | for(int i = start; (i <= num && xthPower[i] <= num); ++i) { 92 | int idx = num - xthPower[i]; 93 | if(idx >= 0 && idx <= n) { 94 | count = (count + dp[idx][i + 1]) % MOD; 95 | } 96 | } 97 | 98 | dp[num][start] = count; 99 | } 100 | } 101 | 102 | return dp[n][1]; 103 | } 104 | 105 | public: 106 | int numberOfWays(int n, int x) { 107 | precomputeXthPower(n, x); 108 | return solveWith2DTable(n, x); 109 | } 110 | }; 111 | 112 | ----------------------------------------------------------------------------------------------------------------------------------------------------- 113 | 114 | Topics: Dynamic Programming | Biweekly Contest 109 115 | Link : https://leetcode.com/problems/ways-to-express-an-integer-as-sum-of-powers/description/ 116 | -------------------------------------------------------------------------------- /Dynamic Programming/Partition DP/3 - Count Digit Groupings Of A Number.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the count of all `n` digit numbers whose sum of digits is `sum`. Leading 0’s are not counted as digits ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | /* 5 | REGARDING MY REASONING ON THE LIMIT OF 901 :- 6 | -> Constraints: 7 | 1 <= n <= 100 8 | str[i] ∈ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 9 | 10 | -> In the worst case, the size could be 100 and the maximum digit could be 9. 11 | Considering this the maximum sum could be 100*9 = 900, 12 | Due to 0-based indexing of the array, To fit 900 in the dp array the size must be 901. 13 | */ 14 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 15 | 16 | class TopDown { 17 | int n; 18 | 19 | // O(N^N) & O(N) 20 | int solveWithoutMemo(string& str, int startIndex, int prevSum) { 21 | if(startIndex == n) // Edge case: If no values are left, then you've created one valid grouping 22 | return 1; 23 | 24 | int count = 0, currentSum = 0; 25 | 26 | for(int index = startIndex; index < n; ++index) { 27 | currentSum += str[index] - '0'; 28 | if(prevSum <= currentSum) { 29 | count += solveWithoutMemo(str, index + 1, currentSum); 30 | } 31 | } 32 | 33 | return count; 34 | } 35 | 36 | // O(N*N*901) & O(N*901 + N) 37 | int solveWithMemo(vector>& dp, string& str, int startIndex, int prevSum) { 38 | if(startIndex == n) // Edge case: If no values are left, then you've created one valid grouping 39 | return 1; 40 | 41 | if(dp[startIndex][prevSum] != -1) 42 | return dp[startIndex][prevSum]; 43 | 44 | int count = 0, currentSum = 0; 45 | 46 | for(int index = startIndex; index < n; ++index) { 47 | currentSum += str[index] - '0'; 48 | if(prevSum <= currentSum) { 49 | count += solveWithMemo(dp, str, index + 1, currentSum); 50 | } 51 | } 52 | 53 | return dp[startIndex][prevSum] = count; 54 | } 55 | 56 | public: 57 | // Method to count total number of valid groupings, using recursion with memoization - O(N*N*901) & O(N*901) 58 | int countValidGroupings(string& str) { 59 | n = str.size(); 60 | vector> dp(n, vector(901, -1)); 61 | return solveWithMemo(dp, str, 0, 0); 62 | } 63 | }; 64 | 65 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 66 | 67 | class BottomUp { 68 | public: 69 | // Method to count total number of valid groupings, using 2D tabulation - O(N*N*901) & O(N*901) 70 | int countValidGroupings(string& str) { 71 | int n = str.size(); 72 | 73 | vector> dp(n + 1, vector(901, 0)); 74 | 75 | // Initialize the edge case 76 | for(int prevSum = 0; prevSum <= 900; ++prevSum) 77 | dp[n][prevSum] = 1; 78 | 79 | for(int startIndex = n-1; startIndex >= 0; --startIndex) { 80 | for(int prevSum = 900; prevSum >= 0; --prevSum) { 81 | int count = 0, currentSum = 0; 82 | for(int index = startIndex; index < n; ++index) { 83 | currentSum += str[index] - '0'; 84 | if(prevSum <= currentSum) { 85 | count += dp[index + 1][currentSum]; 86 | } 87 | } 88 | dp[startIndex][prevSum] = count; 89 | } 90 | } 91 | 92 | return dp[0][0]; 93 | } 94 | }; 95 | 96 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 97 | 98 | Topics: String | Dynamic Programming 99 | Link : https://www.geeksforgeeks.org/problems/count-digit-groupings-of-a-number1520/1 100 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/19 - Minimum Number of Coins for Fruits/19.2 - Minimum Number of Coins for Fruits (Enhanced).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum number of coins needed to acquire all the fruits. The fruit market has the following reward for each fruit: If you purchase the ith fruit at prices[i] coins, you can get any number of the next (i + 1) fruits for free. Note that even if you can take fruit j for free, you can still purchase it for prices[j] coins to receive its reward ~ coded by Hiren 2 | 3 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N + N^N) & O(N) 9 | int solveWithoutMemo(vector& prices, int index) { 10 | if(index >= n) 11 | return 0; 12 | 13 | int jumpLimit = index + 1; 14 | int minCoins = solveWithoutMemo(prices, index + jumpLimit + 1); // We know the total free fruits, hence consider skiping all of them at once 15 | 16 | for(int jump = 1; (jump <= jumpLimit && index + jump <= n); ++jump) { 17 | int nextBuy = solveWithoutMemo(prices, index + jump); // Now consider purchasing the next fruit, hence move to that start point 18 | minCoins = min(minCoins, nextBuy); 19 | } 20 | 21 | return minCoins + prices[index]; 22 | } 23 | 24 | // O(N + N*N) & O(2*N) 25 | int solveWithMemo(vector& dp, vector& prices, int index) { 26 | if(index >= n) 27 | return 0; 28 | 29 | if(dp[index] != -1) 30 | return dp[index]; 31 | 32 | int jumpLimit = index + 1; 33 | int minCoins = solveWithMemo(dp, prices, index + jumpLimit + 1); // We know the total free fruits, hence consider skiping all of them at once 34 | 35 | for(int jump = 1; (jump <= jumpLimit && index + jump <= n); ++jump) { 36 | int nextBuy = solveWithMemo(dp, prices, index + jump); // Now consider purchasing the next fruit, hence move to that start point 37 | minCoins = min(minCoins, nextBuy); 38 | } 39 | 40 | return dp[index] = minCoins + prices[index]; 41 | } 42 | 43 | public: 44 | int minimumCoins(vector& prices) { 45 | n = prices.size(); 46 | vector dp(n, -1); 47 | return solveWithMemo(dp, prices, 0); 48 | } 49 | }; 50 | 51 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 52 | 53 | class BottomUp { 54 | public: 55 | // O(N*N) & O(1*N) 56 | int minimumCoins(vector& prices) { 57 | int n = prices.size(); 58 | 59 | vector dp(n + 1, -1); 60 | dp[n] = 0; 61 | 62 | for(int index = n-1; index >= 0; --index) { 63 | int jumpLimit = index + 1; 64 | int nextIndex = index + jumpLimit + 1; 65 | int minCoins = (nextIndex <= n) ? dp[nextIndex] : 0; 66 | 67 | for(int jump = 1; (jump <= jumpLimit && index + jump <= n); ++jump) { 68 | int nextBuy = dp[index + jump]; 69 | minCoins = min(minCoins, nextBuy); 70 | } 71 | 72 | dp[index] = minCoins + prices[index]; 73 | } 74 | 75 | return dp[0]; 76 | } 77 | }; 78 | 79 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 80 | 81 | Topics: Array | Dynamic Programming | Queue | Heap (Priority Queue) | Monotonic Queue 82 | Link : https://leetcode.com/problems/minimum-number-of-coins-for-fruits/description/ 83 | -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/37.2 - Longest Increasing Path In A Matrix.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Code to find the length of the longest increasing path in matrix. From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed) ~ coded by Hiren 3 | 4 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 5 | 6 | /* 7 | DON'T IGNORE MUST READ: For the bottom-up solution of this problem, I created it and run it but it didn't passed all the testcases. 8 | So I would say there are only 3 problems in the whole series which doesn't contain the bottom-up solution 9 | due to this reason. These 3 problems lies in this folder (Multi-Dimensional DP Folder). 10 | 11 | REGARDING INTUITION OF THE SOLUTION: In the previous solution, we're doing backtracking, In this one we're not doing backtracking. Because If 12 | you notice then It's not required, as we need to consider strictly increasing paths, which means from a cell 13 | (R, C) we'll only move to cells (newR, newC) which contains strictly greater value, which means we'll never 14 | end up having a stack-overflow or endless recursion. 15 | */ 16 | 17 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 18 | 19 | class TopDown { 20 | const vector> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 21 | int M, N; 22 | 23 | bool isValid(int R, int C) { 24 | return R >= 0 && C >= 0 && R < M && C < N; 25 | } 26 | 27 | // O(M*N * 4^(M*N)) & O(M*N) 28 | int solveWithoutMemo(const vector>& grid, int R, int C) { 29 | int maxLength = 1; 30 | 31 | for(auto& dir : directions) { 32 | int newR = R + dir[0]; 33 | int newC = C + dir[1]; 34 | if(isValid(newR, newC) && grid[newR][newC] > grid[R][C]) { 35 | int nextLength = solveWithoutMemo(grid, newR, newC); 36 | maxLength = max(maxLength, nextLength + 1); 37 | } 38 | } 39 | 40 | return maxLength; 41 | } 42 | 43 | // O(M*N + 4*M*N) & O(2*M*N) 44 | int solveWithMemo(vector>& dp, const vector>& grid, int R, int C) { 45 | if(dp[R][C] != -1) 46 | return dp[R][C]; 47 | 48 | int maxLength = 1; 49 | 50 | for(auto& dir : directions) { 51 | int newR = R + dir[0]; 52 | int newC = C + dir[1]; 53 | if(isValid(newR, newC) && grid[newR][newC] > grid[R][C]) { 54 | int nextLength = solveWithMemo(dp, grid, newR, newC); 55 | maxLength = max(maxLength, nextLength + 1); 56 | } 57 | } 58 | 59 | return dp[R][C] = maxLength; 60 | } 61 | 62 | public: 63 | // Method to find the length of the longest increasing path in the matrix, using recursion with memoization - O(N*M) & O(N*M) 64 | int longestIncreasingPath(vector>& grid) { 65 | M = grid.size(), N = grid[0].size(); 66 | int result = 0; 67 | 68 | vector> dp(M, vector(N, -1)); 69 | 70 | for(int R = 0; R < M; ++R) 71 | for(int C = 0; C < N; ++C) 72 | result = max(result, solveWithMemo(dp, grid, R, C)); 73 | 74 | return result; 75 | } 76 | }; 77 | 78 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 79 | 80 | Topics: Array | Dynamic Programming | Depth-First Search | Breadth-First Search | Graph | Topological Sort | Memoization | Matrix 81 | Link : https://leetcode.com/problems/longest-increasing-path-in-a-matrix/description/ 82 | -------------------------------------------------------------------------------- /Dynamic Programming/Partition DP/12 - Minimum Cost To Split An Array.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum possible cost of a split of the given array. Split the array into some number of non-empty subarrays. The cost of a split is the sum of the importance value of each subarray in the split. The importance value of a subarray is k + trimmed(subarray).length ~ coded by Hiren 2 | 3 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(N^N) & O(N*1000) 9 | int solveWithoutMemo(vector& nums, int k, int start_i) { 10 | if(start_i == n) 11 | return 0; 12 | 13 | vector freq(1000); 14 | 15 | int trimmedSubArrLen = 0; 16 | int minCost = INT_MAX; 17 | 18 | for(int i = start_i; i < n; ++i) { 19 | int num = nums[i]; 20 | freq[num]++; 21 | trimmedSubArrLen += (freq[num] == 2 ? 2 : 0); 22 | trimmedSubArrLen += freq[num] > 2; 23 | int importanceVal = k + trimmedSubArrLen; 24 | int nextCost = solveWithoutMemo(nums, k, i + 1); 25 | minCost = min(minCost, importanceVal + nextCost); 26 | } 27 | 28 | return dp[start_i] = minCost; 29 | } 30 | 31 | // O(N*N) & O(N+N*1000) 32 | int solveWithMemo(vector& dp, vector& nums, int k, int start_i) { 33 | if(start_i == n) 34 | return 0; 35 | 36 | if(dp[start_i] != -1) 37 | return dp[start_i]; 38 | 39 | vector freq(1000); 40 | 41 | int trimmedSubArrLen = 0; 42 | int minCost = INT_MAX; 43 | 44 | for(int i = start_i; i < n; ++i) { 45 | int num = nums[i]; 46 | freq[num]++; 47 | trimmedSubArrLen += (freq[num] == 2 ? 2 : 0); 48 | trimmedSubArrLen += freq[num] > 2; 49 | int importanceVal = k + trimmedSubArrLen; 50 | int nextCost = solveWithMemo(dp, nums, k, i + 1); 51 | minCost = min(minCost, importanceVal + nextCost); 52 | } 53 | 54 | return dp[start_i] = minCost; 55 | } 56 | 57 | public: 58 | int minCost(vector& nums, int k) { 59 | n = nums.size(); 60 | vector dp(n, -1); 61 | return solveWithMemo(dp, nums, k, 0); 62 | } 63 | }; 64 | 65 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 66 | 67 | class BottomUp { 68 | public: 69 | // O(N*N) & O(N+1000) 70 | int minCost(vector& nums, int k) { 71 | int n = nums.size(); 72 | 73 | vector dp(n + 1, INT_MAX); 74 | dp[n] = 0; // Initialize the edge case 75 | 76 | for(int start_i = n-1; start_i >= 0; --start_i) { 77 | vector freq(1000); 78 | 79 | int trimmedSubArrLen = 0; 80 | int minCost = INT_MAX; 81 | 82 | for(int i = start_i; i < n; ++i) { 83 | int num = nums[i]; 84 | freq[num]++; 85 | trimmedSubArrLen += (freq[num] == 2 ? 2 : 0); 86 | trimmedSubArrLen += freq[num] > 2; 87 | int importanceVal = k + trimmedSubArrLen; 88 | int nextCost = dp[i + 1]; 89 | minCost = min(minCost, importanceVal + nextCost); 90 | } 91 | 92 | dp[start_i] = minCost; 93 | } 94 | 95 | return dp[0]; 96 | } 97 | }; 98 | 99 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 100 | 101 | Topics: Array | Hash Table | Dynamic Programming | Counting 102 | Link : https://leetcode.com/problems/minimum-cost-to-split-an-array/description/ 103 | -------------------------------------------------------------------------------- /Backtracking/Subsets I.cpp: -------------------------------------------------------------------------------- 1 | // Program to find all the possible subsets (the solution set must not contain duplicate subsets) ~ coded by Hiren 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // #1 Backtracking approach: 9 | class Backtracking_V1 { 10 | vector> allSubsets; 11 | int N; 12 | 13 | void getAllUniqueSubsets(vector& nums, vector& currSubset, int startIdx) { 14 | allSubsets.push_back(currSubset); 15 | 16 | for(int J = startIdx; J < N; ++J) { 17 | currSubset.push_back(nums[J]); // Include the element (perform the action) 18 | getAllUniqueSubsets(nums, currSubset, J+1); 19 | currSubset.pop_back(); // Exclude the element (revert the action) 20 | } 21 | } 22 | 23 | public: 24 | // Method to find all the possible subsets - O(2^N * N) & O(2^N * N) : Where N is the size of "nums" (there could be 2^N possible subsets) 25 | vector> subsets(vector& nums) { 26 | N = nums.size(); 27 | vector currSubset; 28 | getAllUniqueSubsets(nums, currSubset, 0); 29 | return allSubsets; 30 | } 31 | }; 32 | 33 | // #2 Backtracking approach: 34 | class Backtracking_V2 { 35 | vector> allSubsets; 36 | int N; 37 | 38 | void getAllUniqueSubsets(vector& nums, vector& currSubset, int J) { 39 | // Edge case: When all the elements are exhausted 40 | if(J >= N) { 41 | allSubsets.push_back(currSubset); 42 | return; 43 | } 44 | 45 | // Include the element and move one 46 | currSubset.push_back(nums[J]); 47 | getAllUniqueSubsets(nums, currSubset, J+1); 48 | currSubset.pop_back(); 49 | 50 | // Exclude the element and move on 51 | getAllUniqueSubsets(nums, currSubset, J+1); 52 | } 53 | 54 | public: 55 | // Method to find all the possible subsets - O(2^N * N) & O(2^N * N) : Where N is the size of "nums" (there could be 2^N possible subsets) 56 | vector> subsets(vector& nums) { 57 | N = nums.size(); 58 | vector currSubset; 59 | getAllUniqueSubsets(nums, currSubset, 0); 60 | return allSubsets; 61 | } 62 | }; 63 | 64 | // Driver code 65 | int main() { 66 | // Tracks the user wants to perform the operation or not 67 | bool userWantsOperation = true; 68 | 69 | while(userWantsOperation) { 70 | // Controls console clearance for both "windows" and "linux" user 71 | system("cls || clear"); 72 | 73 | // Input the array size 74 | int N; 75 | cout<<"Enter the size of array: "; 76 | cin>>N; 77 | 78 | // Check the given size is valid or not 79 | if(N <= 0) { 80 | cout<<"Enter a valid size, application expects a positive integer!"; 81 | return 0; 82 | } 83 | 84 | // Stores the array values 85 | vector nums(N, 0); 86 | 87 | // Input the array values 88 | cout<<"Enter unique values for the array: "; 89 | for(int J = 0; J < N; ++J) { 90 | cin>>nums[J]; 91 | } 92 | 93 | // Call to get the list of all the possible subsets 94 | Backtracking_V2 bt; 95 | vector> allSubsets = bt.subsets(nums); 96 | 97 | // Print the values of each subset 98 | cout<<"\nList of all the possible subsets:\n"; 99 | for(auto& currSubset : allSubsets) { 100 | int size = currSubset.size(); 101 | cout<<"["; 102 | for(int J = 0; J < size; ++J) { 103 | cout<>userChoice; 113 | userWantsOperation = (userChoice == 'R' ? true : false); 114 | } 115 | 116 | return 0; 117 | } 118 | /* 119 | Topics: Array | Backtracking 120 | Link: https://leetcode.com/problems/subsets/description/ 121 | */ 122 | -------------------------------------------------------------------------------- /Dynamic Programming/String DP/11 - Count Palindromic Substrings.cpp: -------------------------------------------------------------------------------- 1 | // Code to count the total number of palindromic substrings of the given string ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | bool isPalindrome(vector>& dp, string& s, int start, int end) { 7 | // Edge case: If no letters exists then string is palindrome 8 | if(start >= end) 9 | return true; 10 | 11 | // Edge case: If both letters don't match then string can't be palindrome 12 | if(s[start] != s[end]) 13 | return false; 14 | 15 | if(dp[start][end] != -1) 16 | return dp[start][end]; 17 | 18 | return dp[start][end] = isPalindrome(dp, s, start + 1, end - 1); 19 | } 20 | 21 | public: 22 | // Method to count the number of palindromic substrings, using recursion with memoization - O(N^2) & O(N^2) 23 | int countSubstrings(string& s) { 24 | int n = s.size(); 25 | int count = 0; 26 | 27 | vector> dp(n, vector(n, -1)); 28 | 29 | for(int i = 0; i < n; ++i) // Check all the substrings and count the palindromes 30 | for(int j = i; j < n; ++j) 31 | if(isPalindrome(dp, s, i, j)) 32 | count++; 33 | 34 | return count; 35 | } 36 | }; 37 | // Note: Without Memoization DP The Time Complexity Is O(N^3). 38 | 39 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 40 | 41 | class BottomUpBrute { 42 | public: 43 | // Method to count the number of palindromic substrings, using 2D tabulation - O(N^2) & O(N^2) 44 | int countSubstrings(string& s) { 45 | int n = s.size(); 46 | int count = 0; 47 | 48 | vector> dp(n + 1, vector(n, false)); 49 | 50 | for(int start = n-1; start >= 0; --start) // Initialize the first edge case 51 | for(int end = 0; end <= n-1; ++end) 52 | if(start >= end) 53 | dp[start][end] = true; 54 | 55 | for(int start = n-1; start >= 0; --start) // Fill the rest of table 56 | for(int end = 0; end <= n-1; ++end) 57 | if(start < end && s[start] == s[end]) 58 | dp[start][end] = (end - 1 >= 0) ? dp[start + 1][end - 1] : false; 59 | 60 | for(int i = 0; i < n; ++i) // Check all the substrings and count the palindromes 61 | for(int j = i; j < n; ++j) 62 | if(dp[i][j]) 63 | count++; 64 | 65 | return count; 66 | } 67 | }; 68 | 69 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 70 | 71 | class BottomUpEnhanced { 72 | public: 73 | // Method to count the number of palindromic substrings, using 2D tabulation - O(N^2) & O(N^2) 74 | int countSubstrings(string& s) { 75 | int n = s.size(); 76 | int count = 0; 77 | 78 | vector> dp(n + 1, vector(n, false)); 79 | 80 | for(int start = n-1; start >= 0; --start) // Initiailze the first edge case 81 | for(int end = 0; end <= n-1; ++end) 82 | if(start >= end) 83 | dp[start][end] = true; 84 | 85 | for(int start = n-1; start >= 0; --start) { // Fill rest of the table and count the palindromes 86 | for(int end = 0; end <= n-1; ++end) { 87 | if(start < end && s[start] == s[end]) 88 | dp[start][end] = (end - 1 >= 0) ? dp[start + 1][end - 1] : false; 89 | if(end >= start && dp[start][end]) 90 | count++; 91 | } 92 | } 93 | 94 | return count; 95 | } 96 | }; 97 | 98 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 99 | 100 | Topics: Two Pointers | String | Dynamic Programming 101 | Link : https://leetcode.com/problems/palindromic-substrings/description/ -------------------------------------------------------------------------------- /Dynamic Programming/Multi Dimensional DP/24 - Paint House.cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum cost of painting all the houses such that no adjacent houses are painted with the same color ~ coded by Hiren 2 | 3 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | // O(2^N) & O(N) 9 | int solveWithoutMemo(vector>& costs, int house, int prevColor) { 10 | if(house == n) 11 | return 0; 12 | 13 | int minCost = INT_MAX; 14 | 15 | for(int color = 0; color < 3; ++color) 16 | if(color != prevColor) 17 | minCost = min(minCost, costs[house][color] + solveWithoutMemo(costs, house + 1, color)); 18 | 19 | return minCost; 20 | } 21 | 22 | // O(2*N*4) & O(N*4+N) 23 | int solveWithMemo(vector>& dp, vector>& costs, int house, int prevColor) { 24 | if(house == n) 25 | return 0; 26 | 27 | if(dp[house][prevColor] != -1) 28 | return dp[house][prevColor]; 29 | 30 | int minCost = INT_MAX; 31 | 32 | for(int color = 0; color < 3; ++color) 33 | if(color != prevColor) 34 | minCost = min(minCost, costs[house][color] + solveWithMemo(dp, costs, house + 1, color)); 35 | 36 | return minCost; 37 | } 38 | 39 | public: 40 | // Method to find minimum cost to paint all houses, using recursion with memoization - O(N) & O(N) 41 | int minCost(vector>& costs) { 42 | n = costs.size(); 43 | vector> dp(n, vector(4, -1)); 44 | return solveWithMemo(dp, costs, 0, 3); // I passed 3 as previously-chosen-color but you can pass any value just avoid the columns indeces 0, 1, 2 45 | } 46 | }; 47 | 48 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 49 | 50 | class BottomUp { 51 | int n; 52 | 53 | // O(N*4*3) & O(N*4) 54 | int solveWith2DTable(vector>& costs) { 55 | vector> dp(n + 1, vector(4, -1)); 56 | 57 | for(int prevColor = 0; prevColor <= 3; ++prevColor) // Init edge case 58 | dp[n][prevColor] = 0; 59 | 60 | for(int house = n-1; house >= 0; --house) { 61 | for(int prevColor = 0; prevColor <= 3; ++prevColor) { 62 | int minCost = INT_MAX; 63 | 64 | for(int color = 0; color < 3; ++color) { 65 | if(color != prevColor) { 66 | minCost = min(minCost, costs[house][color] + dp[house + 1][color]); 67 | } 68 | } 69 | 70 | dp[house][prevColor] = minCost; 71 | } 72 | } 73 | 74 | return dp[0][3]; 75 | } 76 | 77 | // O(N*4*3) & O(2*4) 78 | int solveWith1DTable(vector>& costs) { 79 | vector nextRow(4, -1), idealRow(4, -1); 80 | 81 | for(int prevColor = 0; prevColor <= 3; ++prevColor) 82 | nextRow[prevColor] = 0; 83 | 84 | for(int house = n-1; house >= 0; --house) { 85 | for(int prevColor = 0; prevColor <= 3; ++prevColor) { 86 | int minCost = INT_MAX; 87 | 88 | for(int color = 0; color < 3; ++color) { 89 | if(color != prevColor) { 90 | minCost = min(minCost, costs[house][color] + nextRow[color]); 91 | } 92 | } 93 | 94 | idealRow[prevColor] = minCost; 95 | } 96 | nextRow = idealRow; 97 | } 98 | 99 | return nextRow[3]; 100 | } 101 | 102 | public: 103 | int minCost(vector>& costs) { 104 | n = costs.size(); 105 | return solveWith1DTable(costs); 106 | } 107 | }; 108 | 109 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 110 | 111 | Topics: Array | Dynamic Programming 112 | Links : https://www.naukri.com/code360/problems/paint-house_1460385 113 | https://leetcode.com/problems/paint-house/description/ 114 | -------------------------------------------------------------------------------- /Dynamic Programming/1D DP/14 - Minimum Cost For Tickets/14.2 - Minimum Cost For Tickets (Binary Search).cpp: -------------------------------------------------------------------------------- 1 | // Code to find the minimum number of dollars you need to travel every day in the given list of days ~ coded by Hiren 2 | 3 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 4 | 5 | class TopDown { 6 | int n; 7 | 8 | int getNextStartDay(vector& days, int target, int start) { 9 | int end = n-1, answer = n; 10 | 11 | while(start <= end) { 12 | int mid = start + (end - start) / 2; 13 | 14 | if(days[mid] >= target) { 15 | answer = mid; 16 | end = mid - 1; 17 | } else { 18 | start = mid + 1; 19 | } 20 | } 21 | 22 | return answer; 23 | } 24 | 25 | // O(3^N * LogN) & O(N) 26 | int solveWithoutMemo(vector& days, vector& costs, int idx) { 27 | if(idx == n) 28 | return 0; 29 | 30 | // There are three possibilities to perform at each day 31 | int oneDayPass = costs[0] + solveWithoutMemo(days, costs, getNextStartDay(days, days[idx] + 1, idx + 1)); // To buy 1-day pass 32 | int sevenDayPass = costs[1] + solveWithoutMemo(days, costs, getNextStartDay(days, days[idx] + 7, idx + 1)); // To buy 7-day pass 33 | int thirtyDayPass = costs[2] + solveWithoutMemo(days, costs, getNextStartDay(days, days[idx] + 30, idx + 1)); // To buy 30-day pass 34 | 35 | return min({oneDayPass, sevenDayPass, thirtyDayPass}); 36 | } 37 | 38 | // O(3*NLogN) & O(2*N) 39 | int solveWithMemo(vector& dp, vector& days, vector& costs, int idx) { 40 | if(idx == n) 41 | return 0; 42 | 43 | if(dp[idx] != -1) 44 | return dp[idx]; 45 | 46 | // There are three possibilities to perform at each day 47 | int oneDayPass = costs[0] + solveWithMemo(dp, days, costs, getNextStartDay(days, days[idx] + 1, idx + 1)); // To buy 1-day pass 48 | int sevenDayPass = costs[1] + solveWithMemo(dp, days, costs, getNextStartDay(days, days[idx] + 7, idx + 1)); // To buy 7-day pass 49 | int thirtyDayPass = costs[2] + solveWithMemo(dp, days, costs, getNextStartDay(days, days[idx] + 30, idx + 1)); // To buy 30-day pass 50 | 51 | return dp[idx] = min({oneDayPass, sevenDayPass, thirtyDayPass}); 52 | } 53 | 54 | public: 55 | int mincostTickets(vector& days, vector& costs) { 56 | n = days.size(); 57 | vector dp(n, -1); 58 | return solveWithMemo(dp, days, costs, 0); 59 | } 60 | }; 61 | 62 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 63 | 64 | class BottomUp { 65 | int n; 66 | 67 | int getNextStartDay(vector& days, int target, int start) { 68 | int end = n-1, answer = n; 69 | 70 | while(start <= end) { 71 | int mid = start + (end - start) / 2; 72 | 73 | if(days[mid] >= target) { 74 | answer = mid; 75 | end = mid - 1; 76 | } else { 77 | start = mid + 1; 78 | } 79 | } 80 | 81 | return answer; 82 | } 83 | 84 | public: 85 | // O(NLogN) & O(N) 86 | int mincostTickets(vector& days, vector& costs) { 87 | n = days.size(); 88 | 89 | vector dp(n + 1, -1); 90 | dp[n] = 0; 91 | 92 | for(int idx = n-1; idx >= 0; --idx) { 93 | int oneDayPass = costs[0] + dp[getNextStartDay(days, days[idx] + 1, idx + 1)]; 94 | int sevenDayPass = costs[1] + dp[getNextStartDay(days, days[idx] + 7, idx + 1)]; 95 | int thirtyDayPass = costs[2] + dp[getNextStartDay(days, days[idx] + 30, idx + 1)]; 96 | dp[idx] = min({oneDayPass, sevenDayPass, thirtyDayPass}); 97 | } 98 | 99 | return dp[0]; 100 | } 101 | }; 102 | 103 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- 104 | 105 | Topics: Array | Binary Search | Dynamic Programming 106 | Link : https://leetcode.com/problems/minimum-cost-for-tickets/description/ 107 | --------------------------------------------------------------------------------