13. Dynamic Programming#
Theory#
Use DP when the problem has optimal substructure (optimal solution built from optimal subsolutions) and overlapping subproblems (same states recomputed in naive recursion).
Five-step framework#
- Define state — what does
dp[i]ordp[i][j]represent? Name it precisely. - Recurrence — how does state
irelate to smaller states? - Base cases — smallest subproblems with known answers.
- Iteration order — fill table so dependencies are ready (often left→right, or by increasing capacity).
- Reconstruction — if path required, store parent pointers or backtrack from final state.
Top-down vs bottom-up#
| Top-down (memo) | Bottom-up (tabulation) | |
|---|---|---|
| Code | @cache / @lru_cache on recursion |
nested loops filling table |
| Space | O(states) memo + O(depth) stack | O(states) table |
| When | quick to write; sparse states | need full table; space optimization |
from functools import cache
@cache
def dp(i: int) -> int:
if base(i):
return base_value
return combine(dp(i - 1), dp(i - 2))
Common DP families#
| Family | State hint | Examples |
|---|---|---|
| 0/1 knapsack | include/exclude each item | LC 416, 494 |
| Unbounded knapsack | unlimited use per item | LC 322, 518 |
| LCS / edit distance | two string indices | LC 1143, 72 |
| Grid path | (row, col) |
LC 62, 64 |
| Linear sequence | dp[i] from prior indices |
LC 300 (LIS), 198 (house robber) |
| Tree DP | return value per subtree | LC 337, 124 |
Pitfalls#
- If a greedy choice is provably optimal, DP is overkill — state why greedy fails before committing to DP.
- Space optimize 1D rolling arrays when recurrence only needs last
krows (knapsack: one row, iterate right-to-left). - State explosion: if dimensions exceed ~10⁶, look for structure (monotonic queue, greedy, or math).
See also: Recursion for memoization and backtracking contrast.
Problems at a glance#
| LC | Problem | |
|---|---|---|
| 416 | Equal Sum Partition | ↗ |
| 494 | Target Sum | ↗ |
| 1049 | Last Stone Weight II | ↗ |
| 518 | Coin Change I – Maximum Number of Ways | ↗ |
| 322 | Coin Change II – Minimum Number of Coins | ↗ |
| 1891 | Maximum Ribbon Cut | ↗ |
| 516 | Longest Palindromic Subsequence | ↗ |
| 5 | Longest Palindromic Substring | ↗ |
| 647 | Count of Palindromic Substrings | ↗ |
| 1312 | Minimum Number of Insertions to Make a String Palindrome | ↗ |
| 72 | Edit Distance | ↗ |
| 300 | Longest Increasing Subsequence | ↗ |
| 368 | Largest Divisible Subset | ↗ |
| 354 | Russian Doll Envelopes | ↗ |
| 646 | Maximum Length of Pair Chain | ↗ |
| 673 | Number of Longest Increasing Subsequence | ↗ |
| 740 | Delete and Earn | ↗ |
| 1048 | Longest String Chain | ↗ |
| 87 | Scramble String | ↗ |
| 887 | Super Egg Drop | ↗ |
| 1039 | Minimum Score Triangulation of Polygon | ↗ |
| 1130 | Minimum Cost Tree From Leaf Values | ↗ |
| 312 | Burst Balloons | ↗ |
| 70 | Climbing Stairs | ↗ |
| 198 | House Robber I | ↗ |
| 213 | House Robber II | ↗ |
| 91 | Decode Ways | ↗ |
| 1137 | Tribonacci Number | ↗ |
| 53 | Maximum Subarray | ↗ |
| 152 | Maximum Product Subarray | ↗ |
| 1749 | Maximum Absolute Sum of Any Subarray | ↗ |
| 543 | Diameter of Binary Tree | ↗ |
| 124 | Maximum Path Sum in Binary Tree | ↗ |
| 508 | Most Frequent Subtree Sum | ↗ |
| 62 | Unique Paths in Grid | ↗ |
| 64 | Minimum Path Sum in Grid | ↗ |
| 120 | Triangle | ↗ |
| 221 | Maximal Square | ↗ |
| 931 | Minimum Falling Path Sum | ↗ |
| 174 | Dungeon Game | ↗ |
| 741 | Cherry Pickup | ↗ |
| 44 | Wildcard Matching | ↗ |
| 10 | Regular Expression Matching | ↗ |
| 698 | Partition to K Equal Sum Subsets | ↗ |
| 847 | Shortest Path Visiting All Nodes | ↗ |
| 1349 | Maximum Students Taking Exam | ↗ |
| 943 | Find the Shortest Superstring | ↗ |
| 1986 | Minimum Number of Work Sessions to Finish Tasks | ↗ |
| 1434 | Number of Ways to Wear Different Hats to Each Other | ↗ |
| 2305 | Fair Distribution of Cookies | ↗ |
| 233 | Number of Digit One | ↗ |
| 600 | Non-negative Integers without Consecutive Ones | ↗ |
| 902 | Numbers At Most N Given Digit Set | ↗ |
| 1012 | Numbers With Repeated Digits | ↗ |
| 688 | Knight Probability in Chessboard | ↗ |
| 808 | Soup Servings | ↗ |
| 837 | New 21 Game | ↗ |
| 121 | Best Time to Buy and Sell Stock | ↗ |
| 122 | Best Time to Buy and Sell Stock II | ↗ |
| 123 | Best Time to Buy and Sell Stock III | ↗ |
| 188 | Best Time to Buy and Sell Stock IV | ↗ |
| 309 | Best Time to Buy and Sell Stock with Cooldown | ↗ |
| 714 | Best Time to Buy and Sell Stock with Transaction Fee | ↗ |
| 968 | Binary Tree Cameras | ↗ |
0-1 Knapsack#
Problem 1: Subset Sum (GeeksforGeeks)#
Problem Statement
Given a set of non-negative integers arr[] and a target sum sum, determine whether a subset of the array exists whose elements add up to exactly sum. Each element can be used at most once.
Example 1:
Input: arr = [3, 34, 4, 12, 5, 2], sum = 9
Output: true
Explanation: Subset {4, 5} sums to 9.
Example 2:
Input: arr = [3, 34, 4, 12, 5, 2], sum = 30
Output: false
Constraints:
1 <= arr.length <= 1000 <= arr[i], sum <= 10⁴
Code and Explanation
dp[i][s] = can first i items form sum s? Skip item i (dp[i-1][s]) or take it if it fits (dp[i-1][s-arr[i-1]]).
Time: O(n × target) | Space: O(n × target)
Single row; iterate
s right-to-left so each item is used at most once per outer loop.
Time: O(n × target) | Space: O(target)
Problem 2: Equal Sum Partition (Leetcode:416)#
Problem Statement
Given an integer array nums, return true if you can partition the array into two subsets such that the sum of the elements in both subsets is equal, or false otherwise.
Example 1:
Input: nums = [1,5,11,5]
Output: true
Explanation: Partition as [1, 5, 5] and [11].
Example 2:
Input: nums = [1,2,3,5]
Output: false
Constraints:
1 <= nums.length <= 2001 <= nums[i] <= 100
Code and Explanation
Equal partition exists iff some subset sums to
total/2. Odd total → impossible.
Time: O(n × sum) | Space: O(sum)
Track all achievable sums in a set; early exit when
target appears.
Time: O(n × sum) worst case | Space: O(sum)
Problem 3: Count of Subset Sum (GeeksforGeeks)#
Problem Statement
Given an array arr[] of non-negative integers and a target sum, count the number of subsets whose elements add up to exactly sum. Each element is used at most once; order does not matter.
Example 1:
Input: arr = [2, 3, 5, 6, 8, 10], sum = 10
Output: 3
Explanation: {2,3,5}, {10}, {2,8}.
Example 2:
Input: arr = [1, 2, 3], sum = 3
Output: 2
Explanation: {1,2}, {3}.
Constraints:
1 <= arr.length <= 1000 <= arr[i], sum <= 10³
Code and Explanation
dp[s] = number of subsets summing to s. Adding item num: dp[s] += dp[s-num]. Right-to-left preserves 0/1 constraint.
Time: O(n × target) | Space: O(target)
Problem 4: Minimum Subset Sum Difference (GeeksforGeeks)#
Problem Statement
Given an array arr[], partition it into two subsets (every element in exactly one subset) such that the absolute difference of their sums is minimized. Return that minimum difference.
Example 1:
Input: arr = [1, 6, 11, 5]
Output: 1
Explanation: Subsets {1, 5, 6} (sum 12) and {11} (sum 11) → |12−11| = 1.
Example 2:
Input: arr = [1, 2, 7, 1, 5]
Output: 0
Explanation: {1, 2, 5} and {7, 1} both sum to 8.
Constraints:
1 <= arr.length <= 300 <= arr[i] <= 50
Code and Explanation
Find largest
s1 ≤ total/2 achievable. Subset sums s1 and total−s1 give minimum diff total − 2×s1.
Time: O(n × total) | Space: O(n × total)
Enumerate all subset sums via set expansion; pick best
s ≤ total/2.
Time: O(n × 2^n) worst case | Space: O(2^n)
Problem 5: Count of Subsets with Given Difference (GeeksforGeeks)#
Problem Statement
Given an array arr[] and an integer D, count subsets where sum(subset1) − sum(subset2) = D. Every element belongs to exactly one subset.
Example 1:
Input: arr = [1, 1, 2, 3], D = 1
Output: 3
Example 2:
Input: arr = [1, 2, 3], D = 1
Output: 2
Constraints:
1 <= arr.length <= 500 <= arr[i], D <= 10³
Code and Explanation
Let
S1 − S2 = D and S1 + S2 = total → S1 = (total + D) / 2. Count subsets summing to S1 (must be integer and feasible).
Time: O(n × target) | Space: O(target)
Problem 6: Target Sum (Leetcode:494)#
Problem Statement
Given an integer array nums and an integer target, assign each element a + or − sign so that the resulting expression equals target. Return the number of ways.
Example 1:
Input: nums = [1,1,1,1,1], target = 3
Output: 5
Example 2:
Input: nums = [1], target = 1
Output: 1
Constraints:
1 <= nums.length <= 200 <= nums[i] <= 10000 <= sum(nums[i]) <= 1000−1000 <= target <= 1000
Code and Explanation
+num contributes to positive subset sum P; −num does not. Need P − (total−P) = target → P = (total + target)/2.
Time: O(n × sum) | Space: O(sum)
Direct recursion with memo on
(index, running_sum). Good for small n ≤ 20.
Time: O(n × sum) | Space: O(n × sum)
Problem 7: Last Stone Weight II (Leetcode:1049)#
Problem Statement
You are given an array of integers stones where stones[i] is the weight of the ith stone. On each turn, pick two stones and smash them: if equal, both destroyed; otherwise the lighter is destroyed and the heavier loses the difference in weight. Return the smallest possible weight of the last remaining stone.
Example 1:
Input: stones = [2,7,4,1,8,1]
Output: 1
Example 2:
Input: stones = [31,26,33,21,40]
Output: 23
Constraints:
1 <= stones.length <= 301 <= stones[i] <= 100
Code and Explanation
Optimal strategy partitions stones into two piles with minimum sum difference — equivalent to minimum subset sum difference. Answer =
total − 2×best.
Time: O(n × total) | Space: O(total)
Unbounded Knapsack#
Problem 1: Rod Cutting (GeeksforGeeks)#
Problem Statement
Given a rod of length n and an array prices[] where prices[i] is the price of a piece of length i+1, determine the maximum revenue obtainable by cutting the rod into pieces and selling them. Each length can be used unlimited times.
Example 1:
Input: n = 8, prices = [1, 5, 8, 9, 10, 17, 17, 20]
Output: 22
Explanation: Cut as 2 + 6 → price 5 + 17 = 22.
Constraints:
1 <= n <= 10³1 <= prices.length <= n
Code and Explanation
dp[L] = max revenue for rod length L. Try every cut size cut; reuse remainder via dp[L−cut] (unbounded).
Time: O(n²) | Space: O(n)
Same recurrence; memo avoids recomputing sub-lengths.
Time: O(n²) | Space: O(n)
Problem 2: Coin Change I – Maximum Number of Ways (Leetcode:518)#
Problem Statement
Given an integer array coins of distinct denominations and an integer amount, return the number of combinations that make up that amount. Each coin may be used an unlimited number of times. The answer fits in a 32-bit integer.
Example 1:
Input: amount = 5, coins = [1,2,5]
Output: 4
Explanation: 5=5, 5=2+2+1, 5=2+1+1+1, 5=1+1+1+1+1.
Example 2:
Input: amount = 3, coins = [2]
Output: 0
Constraints:
1 <= coins.length <= 3001 <= coins[i] <= 50000 <= amount <= 5000
Code and Explanation
Outer loop over coins avoids counting permutations as distinct.
dp[a] += ways to form a−coin.
Time: O(amount × coins) | Space: O(amount)
dp[a][i] = combinations using coins i..end. Take coin (dp[a−coin][i]) or skip (dp[a][i+1]).
Time: O(amount × coins) | Space: O(amount × coins)
Problem 3: Coin Change II – Minimum Number of Coins (Leetcode:322)#
Problem Statement
Given an integer array coins and an integer amount, return the fewest number of coins needed to make up that amount. If impossible, return -1. Each coin may be used unlimited times.
Example 1:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1.
Example 2:
Input: coins = [2], amount = 3
Output: -1
Constraints:
1 <= coins.length <= 121 <= coins[i] <= 2³¹ − 10 <= amount <= 10⁴
Code and Explanation
dp[a] = min coins for amount a. Try every coin: dp[a] = min(dp[a], 1 + dp[a−c]).
Time: O(amount × coins) | Space: O(amount)
Recursive min over all coin choices with memo on
remaining.
Time: O(amount × coins) | Space: O(amount)
Problem 4: Maximum Ribbon Cut (Leetcode:1891)#
Problem Statement
You are given an integer array ribbons and an integer k. You may cut any ribbon into segments of positive integer length (unlimited cuts). Return the maximum length x such that you can obtain at least k ribbons of length x. Return 0 if impossible.
Example 1:
Input: ribbons = [9,7,5], k = 3
Output: 5
Explanation: Cut to get three ribbons of length 5.
Example 2:
Input: ribbons = [7,5,9], k = 4
Output: 4
Constraints:
1 <= ribbons.length <= 10⁵1 <= ribbons[i] <= 10⁵1 <= k <= 10⁹
Code and Explanation
If length
x works, any smaller length works too (monotonic). Binary search the maximum feasible x; check by summing ribbon // x.
Time: O(n log max(ribbons)) | Space: O(1)
Upper bound:
total // k. Same binary search with hi = mid - 1 variant.
Time: O(n log(total/k)) | Space: O(1)
Longest Common Subsequence#
Problem 1: Longest Common Substring (GeeksforGeeks)#
Problem Statement
Given two strings s1 and s2, find the length of the longest common substring (contiguous). Unlike subsequence, characters must be adjacent.
Example 1:
Input: s1 = "ABABC", s2 = "BABCA"
Output: 3
Explanation: "BAB" is the longest common substring.
Example 2:
Input: s1 = "abcd", s2 = "efgh"
Output: 0
Constraints:
1 <= s1.length, s2.length <= 10³
Code and Explanation
dp[i][j] = length of common substring ending at s1[i-1] and s2[j-1]. Reset to 0 on mismatch (implicit). Track global max.
Time: O(m × n) | Space: O(m × n)
Only previous row needed;
val depends on diagonal prev[j-1].
Time: O(m × n) | Space: O(n)
Problem 2: Print Longest Common Subsequence (GeeksforGeeks)#
Problem Statement
Given two strings, return one longest common subsequence (not necessarily unique). If none exists, return "".
Example 1:
Input: s1 = "ABCDGH", s2 = "AEDFHR"
Output: "ADH"
Example 2:
Input: s1 = "AGGTAB", s2 = "GXTXAYB"
Output: "GTAB"
Constraints:
1 <= s1.length, s2.length <= 10³
Code and Explanation
Standard LCS table, then backtrack from
(m,n): match → take char; else move toward larger DP neighbor.
Time: O(m × n) | Space: O(m × n)
Problem 3: Shortest Common Supersequence (GeeksforGeeks)#
Problem Statement
Given two strings s1 and s2, find the length of the shortest string that has both s1 and s2 as subsequences.
Example 1:
Input: s1 = "abac", s2 = "cab"
Output: 5
Explanation: "cabac" has length 5.
Example 2:
Input: s1 = "geek", s2 = "eke"
Output: 5
Constraints:
1 <= s1.length, s2.length <= 10³
Code and Explanation
Supersequence must include all chars of both strings; shared LCS chars counted once:
|SCS| = |s1| + |s2| − LCS.
Time: O(m × n) | Space: O(m × n)
Problem 4: Print Shortest Common Supersequence (GeeksforGeeks)#
Problem Statement
Return the actual shortest common supersequence string (any valid answer if multiple exist).
Example 1:
Input: s1 = "abac", s2 = "cab"
Output: "cabac"
Example 2:
Input: s1 = "geek", s2 = "eke"
Output: "geeke"
Constraints:
1 <= s1.length, s2.length <= 10³
Code and Explanation
Backtrack like LCS print; on mismatch append the char from the side we move away from. Append leftovers at end.
Time: O(m × n) | Space: O(m × n)
Problem 5: Minimum Insertions and Deletions to Convert String A to B (GeeksforGeeks)#
Problem Statement
Given strings s1 and s2, find the minimum number of insertions and deletions needed to transform s1 into s2.
Example 1:
Input: s1 = "heap", s2 = "pea"
Output: 3
Explanation: Delete 'h', insert 'p' at start, delete 'p' from end → 2 deletions + 1 insertion.
Example 2:
Input: s1 = "geeksforgeeks", s2 = "geeks"
Output: 8
Constraints:
1 <= s1.length, s2.length <= 10³
Code and Explanation
Keep LCS chars; delete
(m − LCS) from s1, insert (n − LCS) to match s2.
Time: O(m × n) | Space: O(m × n)
Problem 6: Longest Repeating Subsequence (GeeksforGeeks)#
Problem Statement
Find the length of the longest subsequence of a string that appears at least twice in the string (non-overlapping occurrences).
Example 1:
Input: s = "AABEBCDD"
Output: 3
Explanation: "ABD" repeats.
Example 2:
Input: s = "aabb"
Output: 2
Constraints:
1 <= s.length <= 10³
Code and Explanation
LCS of string with itself, but only count matches when
i ≠ j (non-overlapping positions).
Time: O(n²) | Space: O(n²)
Problem 7: Length of Longest Subsequence of A Which is Substring in B (GeeksforGeeks)#
Problem Statement
Given strings A and B, find the length of the longest subsequence of A that is a contiguous substring of B.
Example 1:
Input: A = "ABCD", B = "BACDBD"
Output: 3
Explanation: "ACD" is a subsequence of A and substring "ACD" in B.
Constraints:
1 <= A.length, B.length <= 10³
Code and Explanation
O(n²) substrings of
B; two-pointer check if each is subsequence of A. For large inputs, use DP on (i,j) tracking best contiguous match length in B.
Time: O(m × n²) | Space: O(m × n)
For each start in
B, extend while chars match subsequence order in A.
Time: O(m × n) | Space: O(1)
Problem 8: Subsequence Pattern Matching (GeeksforGeeks)#
Problem Statement
Given strings s and pattern, determine whether pattern appears as a subsequence of s.
Example 1:
Input: s = "abcde", pattern = "ace"
Output: true
Example 2:
Input: s = "abc", pattern = "acb"
Output: false
Constraints:
1 <= s.length <= 10⁴1 <= pattern.length <= 10²
Code and Explanation
Scan
s; advance pattern pointer on match. All pattern chars found in order → true.
Time: O(|s| + |pattern|) | Space: O(1)
dp[i][j] = is pattern[:j] subsequence of s[:i]? Useful when preprocessing for many patterns.
Time: O(m × n) | Space: O(m × n)
Problem 9: Count How Many Times String A Appears as Subsequence in B (GeeksforGeeks)#
Problem Statement
Given strings A (pattern) and B (text), count how many distinct index sequences in B form A as a subsequence.
Example 1:
Input: A = "rabb", B = "rabbbbit"
Output: 4
Example 2:
Input: A = "abc", B = "abcbc"
Output: 3
Constraints:
1 <= A.length <= 1001 <= B.length <= 10³
Code and Explanation
dp[i][j] = ways to form A[:i] as subsequence in B[:j]. Skip B[j-1] or match if chars equal.
Time: O(m × n) | Space: O(m × n)
Problem 10: Longest Palindromic Subsequence (Leetcode:516)#
Problem Statement
Given a string s, return the length of the longest subsequence of s that is a palindrome.
Example 1:
Input: s = "bbbab"
Output: 4
Explanation: "bbbb" is the longest palindromic subsequence.
Example 2:
Input: s = "cbbd"
Output: 2
Constraints:
1 <= s.length <= 1000sconsists of lowercase English letters.
Code and Explanation
dp[i][j] = LPS length in s[i..j]. Match outer chars → +2 inner; else max of excluding one end.
Time: O(n²) | Space: O(n²)
LPS length equals LCS of
s with its reverse.
Time: O(n²) | Space: O(n²)
Problem 11: Longest Palindromic Substring (Leetcode:5)#
Problem Statement
Given a string s, return the longest palindromic substring in s.
Example 1:
Input: s = "babad"
Output: "bab"
Explanation: "aba" is also valid.
Example 2:
Input: s = "cbbd"
Output: "bb"
Constraints:
1 <= s.length <= 1000sconsists of digits and English letters.
Code and Explanation
Try each center (odd and even length palindromes); expand while chars match.
Time: O(n²) | Space: O(1)
dp[i][j] true if s[i..j] palindrome; fill by increasing length.
Time: O(n²) | Space: O(n²)
Problem 12: Count of Palindromic Substrings (Leetcode:647)#
Problem Statement
Given a string s, return the number of palindromic substrings in it.
Example 1:
Input: s = "abc"
Output: 3
Example 2:
Input: s = "aaa"
Output: 6
Constraints:
1 <= s.length <= 1000sconsists of lowercase English letters.
Code and Explanation
Each expansion counts one palindrome; cover odd and even centers.
Time: O(n²) | Space: O(1)
Same palindrome DP as LPS substring; count
True entries.
Time: O(n²) | Space: O(n²)
Problem 13: Minimum Number of Deletions to Make a String Palindrome (GeeksforGeeks)#
Problem Statement
Find the minimum number of deletions required to make a string a palindrome.
Example 1:
Input: s = "aebcbda"
Output: 2
Explanation: Delete 'e' and 'c' → "abdba".
Example 2:
Input: s = "geeksforgeeks"
Output: 8
Constraints:
1 <= s.length <= 10³
Code and Explanation
Chars in LPS need not be deleted; delete the rest:
n − LPS.
Time: O(n²) | Space: O(n²)
Problem 14: Minimum Number of Insertions to Make a String Palindrome (Leetcode:1312)#
Problem Statement
Given a string s, return the minimum number of insertions needed to make s a palindrome.
Example 1:
Input: s = "zzazz"
Output: 0
Example 2:
Input: s = "mbadm"
Output: 2
Explanation: Insert 'b' and 'd' → "mbadabdm".
Constraints:
1 <= s.length <= 500sconsists of lowercase English letters.
Code and Explanation
Insertions fill missing mirror chars; minimum =
n − longest palindromic subsequence.
Time: O(n²) | Space: O(n²)
Same as deletions version; insert chars not in LPS.
Time: O(n²) | Space: O(n²)
Problem 15: Edit Distance (Leetcode:72 | GeeksforGeeks)#
Problem Statement
Given two strings word1 and word2, return the minimum number of operations to convert word1 to word2. Allowed operations: insert, delete, or replace a character.
Example 1:
Input: word1 = "horse", word2 = "ros"
Output: 3
Example 2:
Input: word1 = "intention", word2 = "execution"
Output: 5
Constraints:
0 <= word1.length, word2.length <= 500word1andword2consist of lowercase English letters.
Code and Explanation
dp[i][j] = min edits for word1[:i] → word2[:j]. Match → no cost; else 1 + min of three operations.
Time: O(m × n) | Space: O(m × n)
Only previous row needed for recurrence.
Time: O(m × n) | Space: O(n)
Longest Increasing Subsequence#
Problem 1: Longest Increasing Subsequence (Leetcode:300)#
Problem Statement
Given an integer array nums, return the length of the longest strictly increasing subsequence.
Example 1:
Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: LIS is [2,3,7,101].
Example 2:
Input: nums = [0,1,0,3,2,3]
Output: 4
Constraints:
1 <= nums.length <= 2500−10⁴ <= nums[i] <= 10⁴
Code and Explanation
dp[i] = LIS length ending at index i. Extend from any prior j with nums[j] < nums[i].
Time: O(n²) | Space: O(n)
tails[k] = smallest tail of an increasing subsequence of length k+1. Binary search placement gives O(n log n).
Time: O(n log n) | Space: O(n)
Problem 2: Largest Divisible Subset (Leetcode:368)#
Problem Statement
Given an integer array nums, return the largest subset such that every pair (a, b) satisfies a % b == 0 or b % a == 0. Return any valid answer.
Example 1:
Input: nums = [1,2,3]
Output: [1,2]
Explanation: [1,3] is also valid.
Example 2:
Input: nums = [1,2,4,8]
Output: [1,2,4,8]
Constraints:
1 <= nums.length <= 10001 <= nums[i] <= 10⁹- All elements are distinct.
Code and Explanation
Sort so divisibility only needs check against smaller elements. Track
parent to reconstruct subset.
Time: O(n²) | Space: O(n)
Same recurrence via memoized DFS; reconstruct by following decreasing chain lengths.
Time: O(n²) | Space: O(n)
Problem 3: Russian Doll Envelopes (Leetcode:354)#
Problem Statement
Given envelopes [width, height], one envelope fits inside another if both dimensions are strictly larger. Return the maximum number of envelopes you can nest.
Example 1:
Input: envelopes = [[5,4],[6,4],[6,7],[2,3]]
Output: 3
Explanation: [2,3] → [5,4] → [6,7].
Example 2:
Input: envelopes = [[1,1],[1,1],[1,1]]
Output: 1
Constraints:
1 <= envelopes.length <= 10⁵envelopes[i].length == 21 <= width_i, height_i <= 10⁵
Code and Explanation
Sort by width ascending, height descending (same width cannot nest). LIS on heights via patience sorting.
Time: O(n log n) | Space: O(n)
Classic LIS on heights after sort; simpler but O(n²).
Time: O(n²) | Space: O(n)
Problem 4: Maximum Length of Pair Chain (Leetcode:646)#
Problem Statement
Given pairs [a, b] where a < b, a chain satisfies pairs[i][1] < pairs[j][0] for consecutive pairs. Return the longest chain length.
Example 1:
Input: pairs = [[1,2],[2,3],[3,4]]
Output: 2
Explanation: [1,2] → [3,4].
Example 2:
Input: pairs = [[1,2],[7,8],[4,5]]
Output: 3
Constraints:
1 <= pairs.length <= 1000−1000 <= pairs[i][0], pairs[i][1] <= 1000
Code and Explanation
Sort by end time; greedily pick next non-overlapping pair. Equivalent to LIS with O(n log n) greedy.
Time: O(n log n) | Space: O(1)
dp[i] = longest chain ending at pair i; extend when prior end < current start.
Time: O(n²) | Space: O(n)
Problem 5: Number of Longest Increasing Subsequence (Leetcode:673)#
Problem Statement
Given an integer array nums, return the number of longest increasing subsequences. Since the answer may be large, return it modulo 10⁹ + 7.
Example 1:
Input: nums = [1,3,5,4,7]
Output: 2
Explanation: [1,3,4,7] and [1,3,5,7].
Example 2:
Input: nums = [2,2,2,2,2]
Output: 5
Constraints:
1 <= nums.length <= 2000−10⁶ <= nums[i] <= 10⁶
Code and Explanation
Track both LIS length ending at
i and count of such LIS. Sum counts where length equals global max.
Time: O(n²) | Space: O(n)
Process left-to-right; Fenwick tree stores best (length, count) for values < current. O(n log n) for large n.
Time: O(n log n) | Space: O(n)
Problem 6: Delete and Earn (Leetcode:740)#
Problem Statement
Given integer array nums, in one move pick any nums[i], earn nums[i] points, and delete all elements equal to nums[i], nums[i]−1, and nums[i]+1. Return the maximum points.
Example 1:
Input: nums = [3,4,2]
Output: 6
Explanation: Delete 4 → earn 4; delete 2 → earn 2.
Example 2:
Input: nums = [2,2,3,3,3,4]
Output: 9
Explanation: Delete all 3's → 9 points.
Constraints:
1 <= nums.length <= 2 × 10⁴1 <= nums[i] <= 10⁴
Code and Explanation
Aggregate points per value. Choosing value
v conflicts with v−1; classic House Robber on the value line.
Time: O(n + max_val) | Space: O(max_val)
At value
v, skip or take earn[v] and jump to v+2.
Time: O(max_val) | Space: O(max_val)
Problem 7: Longest String Chain (Leetcode:1048)#
Problem Statement
Given an array of words where each word differs from its predecessor by exactly one inserted letter, return the length of the longest such word chain. Each word may be used at most once.
Example 1:
Input: words = ["a","b","ba","bca","bda","bdca"]
Output: 4
Explanation: "a" → "ba" → "bda" → "bdca".
Example 2:
Input: words = ["xbc","pcxbcf","xb","cxbc","pcxbc"]
Output: 5
Constraints:
1 <= words.length <= 10001 <= words[i].length <= 16- All strings are lowercase English letters.
Code and Explanation
Sort by length. For each word, try removing one char to find predecessor; extend chain like LIS.
Time: O(n × L²) | Space: O(n)
Memoized DFS from each word backward via one-char deletions.
Time: O(n × L²) | Space: O(n × L)
Matrix Chain Multiplication#
Problem 1: Scramble String (Leetcode:87)#
Problem Statement
Given strings s1 and s2 of the same length, determine if s2 is a scrambled version of s1. A scramble splits s1 into x and y, optionally swaps them, and recursively scrambles each part.
Example 1:
Input: s1 = "great", s2 = "rgeat"
Output: true
Example 2:
Input: s1 = "abcde", s2 = "caebd"
Output: false
Constraints:
s1.length == s2.length1 <= s1.length <= 30s1ands2consist of lowercase English letters.
Code and Explanation
dp[len][i][j] = is s1[i:i+len] scramble of s2[j:j+len]? Try every split k; match direct or swapped children.
Time: O(n⁴) | Space: O(n³)
Same split logic recursively; character-sort prune for early false.
Time: O(n⁴) | Space: O(n³)
Problem 2: Super Egg Drop (Leetcode:887)#
Problem Statement
You have k eggs and a building with n floors. Find the minimum number of moves to determine the critical floor (lowest where egg breaks) with optimal strategy.
Example 1:
Input: k = 1, n = 2
Output: 2
Example 2:
Input: k = 2, n = 6
Output: 3
Constraints:
1 <= k <= 1001 <= n <= 10⁴
Code and Explanation
dp[e][f] = min moves with e eggs and f floors. Drop at mid: worst case is max(break, survive). Binary search optimal mid.
Time: O(k × n log n) | Space: O(k × n)
dp[e] = max floors solvable with e eggs in current moves. Increment moves until dp[k] >= n. O(k × answer).
Time: O(k log n) | Space: O(k)
Problem 3: Minimum Score Triangulation of Polygon (Leetcode:1039)#
Problem Statement
Given n vertices labeled 0..n-1 with values values[i], triangulate the polygon by adding diagonals. Score of triangle (i,j,k) is values[i]*values[j]*values[k]. Return minimum total score.
Example 1:
Input: values = [1,2,3]
Output: 6
Example 2:
Input: values = [3,7,4,5]
Output: 144
Constraints:
n == values.length3 <= n <= 501 <= values[i] <= 100
Code and Explanation
dp[i][j] = min score to triangulate polygon slice from vertex i to j. Pick last triangle vertex k between them.
Time: O(n³) | Space: O(n²)
Same recurrence with memo on
(i, j) interval.
Time: O(n³) | Space: O(n²)
Problem 4: Minimum Cost Tree From Leaf Values (Leetcode:1130)#
Problem Statement
Given positive integers arr, build a binary tree where each node value equals max of its subtree leaves. Cost to merge adjacent nodes is max(left) * max(right). Return minimum total merge cost.
Example 1:
Input: arr = [6,2,4]
Output: 32
Explanation: Merge 2 and 4 (cost 8), then with 6 (cost 48)... optimal gives 32.
Example 2:
Input: arr = [4,11]
Output: 44
Constraints:
2 <= arr.length <= 501 <= arr[i] <= 1000
Code and Explanation
Split interval at
k; merge cost uses max leaf in each half. Classic matrix-chain pattern on array intervals.
Time: O(n³) | Space: O(n²)
Greedy: always merge smaller adjacent max first. Stack tracks decreasing leaf maxima.
Time: O(n) | Space: O(n)
Problem 5: Burst Balloons (Leetcode:312)#
Problem Statement
Given n balloons with integers nums, bursting balloon i adds nums[i-1] * nums[i] * nums[i+1] coins (out-of-bounds treated as 1). Return maximum coins obtainable.
Example 1:
Input: nums = [3,1,5,8]
Output: 167
Example 2:
Input: nums = [1,5]
Output: 10
Constraints:
1 <= nums.length <= 5000 <= nums[i] <= 100
Code and Explanation
Pad with 1s.
dp[l][r] = max coins in open interval (l,r) excluding boundaries. Choose k as last balloon burst inside interval.
Time: O(n³) | Space: O(n²)
Same "last burst" recurrence; memo avoids recomputing intervals.
Time: O(n³) | Space: O(n²)
Fibonacci#
Problem 1: Climbing Stairs (Leetcode:70)#
Problem Statement
You are climbing a staircase with n steps. Each time you can climb 1 or 2 steps. In how many distinct ways can you reach the top?
Example 1:
Input: n = 2
Output: 2
Explanation: 1+1 or 2.
Example 2:
Input: n = 3
Output: 3
Constraints:
1 <= n <= 45
Code and Explanation
dp[i] = dp[i-1] + dp[i-2]: reach step i from one or two steps below. Pure Fibonacci.
Time: O(n) | Space: O(1)
Fibonacci via [[1,1],[1,0]]^n. O(log n) for very large n.
Time: O(log n) | Space: O(1)
Problem 2: House Robber I (Leetcode:198)#
Problem Statement
Given non-negative integers representing money in each house, return the maximum amount you can rob without robbing two adjacent houses.
Example 1:
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (1) and house 3 (3).
Example 2:
Input: nums = [2,7,9,3,1]
Output: 12
Constraints:
1 <= nums.length <= 1000 <= nums[i] <= 400
Code and Explanation
At each house: rob (
prev2 + x) or skip (prev1). Fibonacci-like recurrence on running max.
Time: O(n) | Space: O(1)
Direct recursion: take house
i and jump +2, or skip to i+1.
Time: O(n) | Space: O(n)
Problem 3: House Robber II (Leetcode:213)#
Problem Statement
Houses are arranged in a circle — the first and last house are adjacent. Return the maximum rob amount without robbing adjacent houses.
Example 1:
Input: nums = [2,3,2]
Output: 3
Example 2:
Input: nums = [1,2,3,1]
Output: 4
Constraints:
1 <= nums.length <= 1000 <= nums[i] <= 1000
Code and Explanation
Circle breaks into two cases: exclude first house or exclude last. Run House Robber I on each segment.
Time: O(n) | Space: O(1)
Track states with/without first house taken; forbid first+last together at end.
Time: O(n) | Space: O(n)
Problem 4: Decode Ways (Leetcode:91)#
Problem Statement
Given a string s containing digits, return the number of ways to decode it ('1'→'A' … '26'→'Z'). A valid decoding maps the whole string.
Example 1:
Input: s = "12"
Output: 2
Explanation: "AB" (1,2) or "L" (12).
Example 2:
Input: s = "226"
Output: 3
Constraints:
1 <= s.length <= 100scontains only digits and may contain leading zeros.
Code and Explanation
dp[i] = ways to decode prefix length i. Single digit if not '0'; two-digit if 10–26.
Time: O(n) | Space: O(n)
Only need previous two DP values — Fibonacci-like with validity checks.
Time: O(n) | Space: O(1)
Problem 5: Tribonacci Number (Leetcode:1137)#
Problem Statement
The Tribonacci sequence T(n) satisfies T(0)=0, T(1)=1, T(2)=1, and T(n+3)=T(n)+T(n+1)+T(n+2). Given n, return T(n).
Example 1:
Input: n = 4
Output: 4
Explanation: 0,1,1,2,4.
Example 2:
Input: n = 25
Output: 1389537
Constraints:
0 <= n <= 37
Code and Explanation
Generalized Fibonacci with three-term recurrence; keep last three values.
Time: O(n) | Space: O(1)
Direct memoized recursion; fine for small
n ≤ 37.
Time: O(n) | Space: O(n)
Kadane's Algorithm#
Problem 1: Maximum Subarray (Leetcode:53)#
Problem Statement
Given an integer array nums, find the contiguous subarray with the largest sum and return its sum.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] sums to 6.
Example 2:
Input: nums = [1]
Output: 1
Constraints:
1 <= nums.length <= 10⁵−10⁴ <= nums[i] <= 10⁴
Code and Explanation
curr = max sum ending here; either extend previous subarray or start fresh at x.
Time: O(n) | Space: O(1)
Max subarray lies entirely left, right, or crossing mid. O(n log n) alternative.
Time: O(n log n) | Space: O(log n)
Problem 2: Maximum Product Subarray (Leetcode:152)#
Problem Statement
Given an integer array nums, find a contiguous subarray with the largest product and return the product.
Example 1:
Input: nums = [2,3,-2,4]
Output: 6
Example 2:
Input: nums = [-2,0,-1]
Output: 0
Constraints:
1 <= nums.length <= 2 × 10⁴−10 <= nums[i] <= 10
Code and Explanation
Negative flip makes min product become max. Track both extremes at each step (Kadane variant).
Time: O(n) | Space: O(1)
Forward pass for positive-heavy max; reverse pass catches products spanning negatives. Handle zeros implicitly.
Time: O(n) | Space: O(1)
Problem 3: Maximum Absolute Sum of Any Subarray (Leetcode:1749)#
Problem Statement
Given an integer array nums, return the maximum absolute value of the sum of any non-empty subarray.
Example 1:
Input: nums = [1,-3,2,3,-4]
Output: 5
Explanation: Subarray [2,3] has absolute sum 5.
Example 2:
Input: nums = [2,-5,1,-4,3,-3]
Output: 8
Constraints:
1 <= nums.length <= 10⁵−10⁴ <= nums[i] <= 10⁴
Code and Explanation
Run Kadane for maximum and minimum subarray sums; answer is max of their absolute values.
Time: O(n) | Space: O(1)
Subarray sum = prefix[j] − prefix[i]. Track min/max prefix to maximize absolute difference.
Time: O(n) | Space: O(1)
DP on Trees / Graphs#
Problem 1: Diameter of Binary Tree (Leetcode:543)#
Problem Statement
Given the root of a binary tree, return the length of the diameter — the longest path between any two nodes (path may or may not pass through root).
Example 1:
Input: root = [1,2,3,4,5]
Output: 3
Explanation: Path 4→2→1→3 or 5→2→1→3.
Example 2:
Input: root = [1,2]
Output: 1
Constraints:
1 <= number of nodes <= 10⁴−100 <= Node.val <= 100
Code and Explanation
At each node, diameter through it = left height + right height. Return height upward; track global max.
Time: O(n) | Space: O(h)
Return
(subtree_height, best_diameter_in_subtree) from each DFS call.
Time: O(n) | Space: O(h)
Problem 2: Maximum Path Sum in Binary Tree (Leetcode:124)#
Problem Statement
Given a binary tree, return the maximum path sum of any non-empty path. A path is any sequence of nodes where adjacent nodes are connected; the path need not pass through the root.
Example 1:
Input: root = [1,2,3]
Output: 6
Explanation: Path 2→1→3.
Example 2:
Input: root = [-10,9,20,null,null,15,7]
Output: 42
Explanation: Path 15→20→7.
Constraints:
1 <= number of nodes <= 3 × 10⁴−1000 <= Node.val <= 1000
Code and Explanation
gain(node) = max sum of downward path starting at node (for parent). At node, update global with val + left + right; ignore negative child gains.
Time: O(n) | Space: O(h)
Tuple tracks best downward extension and best path entirely in subtree.
Time: O(n) | Space: O(h)
Problem 3: Most Frequent Subtree Sum (Leetcode:508)#
Problem Statement
Given the root of a binary tree, return all values with the most frequent subtree sum. Subtree sum includes a node and all descendants.
Example 1:
Input: root = [5,2,-3]
Output: [2,-3,4]
Example 2:
Input: root = [5,2,-5]
Output: [2]
Constraints:
1 <= number of nodes <= 10⁴−10⁵ <= Node.val <= 10⁵
Code and Explanation
Postorder computes subtree sum bottom-up; count frequencies in hash map.
Time: O(n) | Space: O(n)
Collect all subtree sums in list, then frequency count. Same complexity, clearer separation.
Time: O(n) | Space: O(n)
Problem 4: Maximum Independent Set in a Tree (GeeksforGeeks)#
Problem Statement
Given an undirected tree with n nodes, find the maximum independent set size — largest subset of nodes with no two adjacent.
Example 1:
Input: n = 7, edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6]]
Output: 4
Explanation: Pick nodes 3,4,5,6.
Example 2:
Input: n = 3, edges = [[0,1],[1,2]]
Output: 2
Constraints:
1 <= n <= 10⁵- Tree is connected and acyclic.
Code and Explanation
take = include node + best skip of children. skip = exclude node + max(take/skip) of each child. Root at 0.
Time: O(n) | Space: O(n)
State
(node, parent, included) memoized. Same recurrence, explicit boolean flag.
Time: O(n) | Space: O(n)
Problem 5: Longest Path in DAG (GeeksforGeeks)#
Problem Statement
Given a weighted directed acyclic graph (DAG) with n nodes and edges [u, v, w], find the longest path (maximum sum of edge weights) in the graph.
Example 1:
Input: n = 6, edges = [[0,1,5],[0,2,3],[1,3,6],[1,2,2],[2,4,4],[2,5,2],[3,4,-1],[4,5,-2]]
Output: 12
Explanation: Path 0→1→3→4→5.
Example 2:
Input: n = 3, edges = [[0,1,1],[1,2,1]]
Output: 2
Constraints:
1 <= n <= 10³- Graph is a DAG (no cycles).
Code and Explanation
Process nodes in topological order; relax edges like longest-path DP. Sources start at 0.
Time: O(V + E) | Space: O(V + E)
DAG allows memoized DFS without cycle handling. Try all start nodes; take global max.
Time: O(V + E) | Space: O(V + E)
2D DP / Grid‑based#
Problem 1: Unique Paths in Grid (Leetcode:62)#
Problem Statement
There is a robot on an m × n grid. The robot starts at the top-left corner (0, 0) and tries to reach the bottom-right corner (m − 1, n − 1). The robot can only move down or right at any point. Given m and n, return the number of unique paths.
Example 1:
Input: m = 3, n = 7
Output: 28
Example 2:
Input: m = 3, n = 2
Output: 3
Explanation: Right→Down→Down, Down→Right→Down, Down→Down→Right.
Constraints:
1 <= m, n <= 100
Code and Explanation
dp[i][j] = paths to cell (i,j). Only from top or left → sum of those two.
Time: O(m × n) | Space: O(m × n)
Problem 2: Minimum Path Sum in Grid (Leetcode:64 | GeeksforGeeks)#
Problem Statement
Given an m × n grid filled with non-negative numbers, find a path from top-left to bottom-right which minimizes the sum of all numbers along its path. You may only move down or right.
Example 1:
Input: grid = [[1,3,1],[1,5,1],[4,2,1]]
Output: 7
Explanation: Path 1→3→1→1→1 sums to 7.
Example 2:
Input: grid = [[1,2,3],[4,5,6]]
Output: 12
Constraints:
m == grid.lengthn == grid[i].length1 <= m, n <= 2000 <= grid[i][j] <= 200
Code and Explanation
dp[i][j] = min cost to reach (i,j). Overwrite grid in place: add min of top/left neighbor.
Time: O(m × n) | Space: O(1)
Recursive min path with memo on
(i,j); equivalent recurrence to bottom-up.
Time: O(m × n) | Space: O(m × n)
Problem 3: Triangle (Leetcode:120)#
Problem Statement
Given a triangle array triangle, return the minimum path sum from top to bottom. Each step you may move to an adjacent number on the row below. Adjacent for index j on row i means indices j or j+1 on row i+1.
Example 1:
Input: triangle = [[2],[3,4],[6,5,7],[4,1,8,3]]
Output: 11
Explanation: 2 + 3 + 5 + 1 = 11.
Example 2:
Input: triangle = [[-10]]
Output: -10
Constraints:
1 <= triangle.length <= 200triangle[0].length == 1triangle[i].length == triangle[i - 1].length + 1−10⁴ <= triangle[i][j] <= 10⁴
Code and Explanation
Start from bottom row; for each cell add min of two children below. Avoids boundary checks.
Time: O(n²) | Space: O(n)
dfs(i,j) = min path sum from (i,j) to bottom.
Time: O(n²) | Space: O(n²)
Problem 4: Maximal Square (Leetcode:221)#
Problem Statement
Given an m × n binary matrix matrix filled with 0s and 1s, find the largest square containing only 1s and return its area.
Example 1:
Input: matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
Output: 4
Example 2:
Input: matrix = [["0","1"],["1","0"]]
Output: 1
Constraints:
m == matrix.lengthn == matrix[i].length1 <= m, n <= 300matrix[i][j]is'0'or'1'.
Code and Explanation
dp[i][j] = side length of largest square ending at (i−1,j−1). On '1', limited by top, left, and diagonal neighbors.
Time: O(m × n) | Space: O(m × n)
Same recurrence with one previous row stored.
Time: O(m × n) | Space: O(n)
Problem 5: Minimum Falling Path Sum (Leetcode:931)#
Problem Statement
Given an n × n array of integers matrix, return the minimum sum of any falling path through the matrix. A falling path starts at any element in the first row and chooses one of the three elements below it (left, center, or right).
Example 1:
Input: matrix = [[2,1,3],[6,5,4],[7,8,9]]
Output: 13
Explanation: 1→5→7.
Example 2:
Input: matrix = [[-19,57],[-40,-5]]
Output: -59
Constraints:
n == matrix.length == matrix[i].length1 <= n <= 200−10⁴ <= matrix[i][j] <= 10⁴
Code and Explanation
dp[j] = min falling sum ending at column j in current row. Extend from three parents above.
Time: O(n²) | Space: O(n)
Overwrite each row with cumulative min path sums.
Time: O(n²) | Space: O(1)
Problem 6: Dungeon Game (Leetcode:174)#
Problem Statement
The demons' dungeon consists of an m × n grid. Each cell has an integer — positive (health gain) or negative (health loss). The knight starts at (0,0) with initial health; he must reach (m−1,n−1) alive. Health must stay strictly positive at all times (including start and end). Return the minimum initial health required.
Example 1:
Input: dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
Output: 7
Explanation: Minimum initial health is 7.
Example 2:
Input: dungeon = [[0]]
Output: 1
Constraints:
m == dungeon.lengthn == dungeon[i].length1 <= m, n <= 200−1000 <= dungeon[i][j] <= 1000
Code and Explanation
dp[i][j] = min health needed entering (i,j) to survive to exit. Work backward from princess cell; clamp health to at least 1.
Time: O(m × n) | Space: O(m × n)
Single row processed right-to-left per row; same reverse recurrence.
Time: O(m × n) | Space: O(n)
Problem 7: Cherry Pickup (Leetcode:741)#
Problem Statement
An n × n grid represents a field of cherries. Each cell is one of: 0 (empty), −1 (thorns/block), or a positive integer (cherries). Starting at (0,0), pick cherries and reach (n−1,n−1) moving only right or down. When you pass a cherry cell, cherries there become 0. Return the maximum cherries collectable. Return 0 if no path exists.
Example 1:
Input: grid = [[0,1,-1],[1,0,-1],[1,1,1]]
Output: 5
Example 2:
Input: grid = [[1,1,-1],[1,-1,1],[-1,1,1]]
Output: 0
Constraints:
n == grid.lengthn == grid[i].length1 <= n <= 50grid[i][j]is −1, 0, or positive.
Code and Explanation
Best forward path to each cell + best backward path from each cell (via reversed grid) − double-counted cell cherry.
Time: O(n²) | Space: O(n²)
Two walkers go start→end simultaneously; state
(r1,r2) at fixed step count avoids revisiting cherries. Standard optimal solution for follow-up constraints.
Time: O(n³) | Space: O(n²)
String‑based DP (Matching / Patterns)#
Problem 1: Wildcard Matching (Leetcode:44)#
Problem Statement
Given an input string s and a pattern p, implement wildcard pattern matching with support for '?' and '*':
'?'Matches any single character.'*'Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial). Return true if s matches p, else false.
Example 1:
Input: s = "aa", p = "a"
Output: false
Example 2:
Input: s = "aa", p = "*"
Output: true
Example 3:
Input: s = "cb", p = "?a"
Output: false
Constraints:
0 <= s.length, p.length <= 2000scontains only lowercase English letters.pcontains only lowercase English letters,'?', or'*'.
Code and Explanation
dp[i][j] = does s[:i] match p[:j]? * matches empty (dp[i][j-1]) or consumes a char (dp[i-1][j]).
Time: O(m × n) | Space: O(m × n)
On mismatch, backtrack to last
* and try matching one more char from s. Linear scan when few stars.
Time: O(m × n) worst case | Space: O(1)
Problem 2: Regular Expression Matching (Leetcode:10)#
Problem Statement
Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*':
'.'Matches any single character.'*'Matches zero or more of the preceding element.
The matching should cover the entire input string. Return true if s matches p.
Example 1:
Input: s = "aa", p = "a"
Output: false
Example 2:
Input: s = "aa", p = "a*"
Output: true
Example 3:
Input: s = "ab", p = ".*"
Output: true
Constraints:
1 <= s.length <= 201 <= p.length <= 20scontains only lowercase English letters.pcontains only lowercase English letters,'.', and'*'.- It is guaranteed that for each occurrence of
'*', there is a valid preceding character.
Code and Explanation
* at p[j-1]: skip pair (dp[i][j-2]) or use preceding char if it matches current s[i-1] (dp[i-1][j]).
Time: O(m × n) | Space: O(m × n)
Mirror tabulation logic recursively; memo on
(i,j) indices.
Time: O(m × n) | Space: O(m × n)
DP with Bitmask#
Problem 1: Partition to K Equal Sum Subsets (Leetcode:698)#
Problem Statement
Given an integer array nums and an integer k, return true if it is possible to divide nums into k non-empty subsets whose sums are all equal.
Example 1:
Input: nums = [4,3,2,3,5,2,1], k = 4
Output: true
Explanation: [5], [1,4], [2,3], [2,3].
Example 2:
Input: nums = [1,2,3,4], k = 3
Output: false
Constraints:
1 <= k <= nums.length <= 161 <= nums[i] <= 10⁴- The frequency of each element is in the range
[1, 4].
Code and Explanation
Build subsets of sum
target; sort descending and skip empty restarts to prune. Bitmask equivalent tracks used array.
Time: O(k × 2^n) worst case | Space: O(n)
mask = used elements; sums[mask] = current partial subset sum mod target. Transition adds one unused index.
Time: O(n × 2^n) | Space: O(2^n)
Problem 2: Traveling Salesman Problem (GeeksforGeeks)#
Problem Statement
Given a complete weighted graph with n cities (vertices), find the minimum cost to visit every city exactly once and return to the starting city. The graph is given as a distance matrix dist[i][j].
Example 1:
Input: dist = [[0,10,15,20],[10,0,35,25],[15,35,0,30],[20,25,30,0]]
Output: 80
Explanation: 0→1→3→2→0 costs 10+25+30+15 = 80.
Constraints:
2 <= n <= 200 <= dist[i][j] <= 10³dist[i][i] == 0
Code and Explanation
dp[mask][u] = min cost to visit set mask, ending at u. Start {0} at city 0; add cities one by one; close tour back to 0.
Time: O(n² × 2^n) | Space: O(n × 2^n)
Same state space; recursive form often easier to write in interviews.
Time: O(n² × 2^n) | Space: O(n × 2^n)
Problem 3: Shortest Path Visiting All Nodes (Leetcode:847)#
Problem Statement
You are given an undirected graph with n nodes labeled 0..n−1. Return the length of the shortest path that visits every node. You may start and stop at any node and revisit nodes/edges.
Example 1:
Input: graph = [[1,2,3],[0],[0],[0]]
Output: 4
Explanation: Path 0→1→0→2→0→3 visits all nodes.
Example 2:
Input: graph = [[1],[0,2,4],[1],[4],[1,3]]
Output: 4
Constraints:
n == graph.length1 <= n <= 120 <= graph[i].length < ngraph[i]does not containi.
Code and Explanation
State = current node + bitmask of visited nodes. Multi-source BFS from every start node; first time mask is full wins.
Time: O(n × 2^n + E × 2^n) | Space: O(n × 2^n)
Precompute all-pairs shortest paths, then Held–Karp over visited sets (Hamiltonian path variant, any start/end).
Time: O(n³ + n² × 2^n) | Space: O(n × 2^n)
Problem 4: Maximum Students Taking Exam (Leetcode:1349)#
Problem Statement
A classroom is represented as an m × n matrix seats where '.' is an empty seat and '#' is a broken seat. Students refuse to sit if another student is directly in front, behind, left, or right. Return the maximum number of students that can take the exam.
Example 1:
Input: seats = [["#",".","#","#",".","#"],[".","#","#","#","#","."],["#",".","#","#",".","#"]]
Output: 4
Example 2:
Input: seats = [[".","#"],["#","#"],["#","."],["#","#"],[".","#"]]
Output: 10
Constraints:
m == seats.lengthn == seats[i].length1 <= m <= 81 <= n <= 8seats[i][j]is'#'or'.'.
Code and Explanation
Each row placement is a bitmask (which seats filled). DP over rows; transition if no vertical/horizontal conflict with previous row.
Time: O(m × 3^n × 2^n) practical | Space: O(2^n)
Same idea with helper functions;
bit_count() gives students placed in row.
Time: O(m × V²) where V = valid masks per row | Space: O(V)
Problem 5: Find the Shortest Superstring (Leetcode:943)#
Problem Statement
Given an array of strings words, return the shortest string that contains each word as a substring. If multiple answers exist, return any of them.
Example 1:
Input: words = ["alex","loves","leetcode"]
Output: "alexlovesleetcode"
Example 2:
Input: words = ["catg","ctaagt","gca","catc","gc","gcatg","gctaagt","catgc","gca","gcatgc","gctaagt","gctaagt"]
Output: "gctaagtcatgc"
Constraints:
1 <= words.length <= 121 <= words[i].length <= 20words[i]consists of lowercase English letters.
Code and Explanation
Precompute max overlap when concatenating
words[i] then words[j]. TSP-style bitmask DP maximizes total overlap; reconstruct order and build string.
Time: O(n² × 2^n + n² × L) | Space: O(n × 2^n)
Problem 6: Minimum Number of Work Sessions to Finish Tasks (Leetcode:1986)#
Problem Statement
You are given tasks[i] = minutes to complete task i and a session time sessionTime. During one session you may work on any subset of tasks, but the total time cannot exceed sessionTime. Return the minimum number of sessions needed to finish all tasks.
Example 1:
Input: tasks = [1,2,3], sessionTime = 3
Output: 2
Example 2:
Input: tasks = [3,1,3,1,3], sessionTime = 8
Output: 2
Constraints:
n == tasks.length1 <= n <= 141 <= tasks[i] <= 101 <= sessionTime <= 15
Code and Explanation
Precompute masks fitting one session. From
mask of finished tasks, add any valid subset s of remaining in one session.
Time: O(3^n) | Space: O(2^n)
Pick one valid session subset, recurse on rest; memo on remaining bitmask.
Time: O(3^n) | Space: O(2^n)
Problem 7: Number of Ways to Wear Different Hats to Each Other (Leetcode:1434)#
Problem Statement
There are n people and 40 types of hats numbered 1..40. hats[i] lists hat numbers person i can wear. Return the number of ways to assign each person a different hat, modulo 10⁹ + 7. Each person gets exactly one hat.
Example 1:
Input: hats = [[3,4],[4,5],[5]]
Output: 1
Example 2:
Input: hats = [[3,5,1],[3,5]]
Output: 4
Constraints:
n == hats.length1 <= n <= 101 <= hats[i].length <= 401 <= hats[i][j] <= 40- All hat numbers are distinct per person.
Code and Explanation
Process hats
1..40; mask = people already assigned. For each hat, assign it to any eligible unassigned person.
Time: O(40 × n × 2^n) | Space: O(2^n)
Skip hat or assign to one person; same state space as bottom-up.
Time: O(40 × n × 2^n) | Space: O(40 × 2^n)
Problem 8: Fair Distribution of Cookies (Leetcode:2305)#
Problem Statement
You are given an integer array cookies where cookies[i] is the number of cookies in bag i, and an integer k. Distribute all bags to k children so each child gets at least one bag. The unfairness is the maximum total cookies any single child receives. Return the minimum unfairness possible.
Example 1:
Input: cookies = [8,15,10,20,8], k = 2
Output: 31
Explanation: [8,15,8] and [10,20].
Example 2:
Input: cookies = [6,1,3,2,2,4,1,2], k = 3
Output: 7
Constraints:
2 <= k <= cookies.length <= 81 <= cookies[i] <= 10⁵
Code and Explanation
Assign each bag to a child; prune when current max already ≥ best. Sort descending for tighter bounds. Small
n ≤ 8 makes this feasible.
Time: O(k^n) with pruning | Space: O(k)
Binary search answer (max load); bitmask checks if remaining bags partition into
children_left groups each ≤ limit.
Time: O(log(sum) × 3^n) | Space: O(2^n)
Digit DP#
Problem 1: Number of Digit One (Leetcode:233)#
Problem Statement
Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
Example 1:
Input: n = 13
Output: 6
Explanation: Digit 1 appears in 1, 10, 11 (twice), 12, 13.
Example 2:
Input: n = 0
Output: 0
Constraints:
0 <= n <= 10⁹
Code and Explanation
State
(pos, count, tight) builds numbers left-to-right. At each position, try digits 0..limit; add to count when digit is 1. tight ensures we never exceed n.
Time: O(log n × 10 × log n) | Space: O(log n)
For each decimal place, count how many times
1 appears there across all numbers ≤ n using high/cur/low digit decomposition.
Time: O(log n) | Space: O(1)
Problem 2: Non-negative Integers without Consecutive Ones (Leetcode:600)#
Problem Statement
Given a positive integer n, return the number of non-negative integers ≤ n whose binary representation contains no two consecutive 1s.
Example 1:
Input: n = 5
Output: 5
Explanation: 0, 1, 2, 4, 5 are valid; 3 (11₂) is not.
Example 2:
Input: n = 1
Output: 2
Constraints:
1 <= n <= 10⁹
Code and Explanation
Build binary strings left-to-right.
prev_one blocks placing another 1 after a 1. Count all valid numbers ≤ n (including 0).
Time: O(log n) | Space: O(log n)
Valid i-bit strings follow Fibonacci. Walk
n's bits; when a 1 is fixed, add counts of all smaller valid prefixes; abort if two consecutive 1s appear.
Time: O(log n) | Space: O(log n)
Problem 3: Numbers At Most N Given Digit Set (Leetcode:902)#
Problem Statement
Given an array of digits digits (no duplicates) and an integer n, return the count of positive integers ≤ n whose decimal representation uses only digits from digits.
Example 1:
Input: digits = ["1","3","5","7"], n = 100
Output: 20
Explanation: 1, 3, 5, 7, 11, 13, … up to 77.
Example 2:
Input: digits = ["1","4","9"], n = 1000000000
Output: 29523
Constraints:
1 <= digits.length <= 9digits[i]is a digit in'1'–'9'- All digits are distinct
1 <= n <= 10⁹
Code and Explanation
started skips leading zeros (we need positive integers). Only digits in allowed may be placed. tight caps the current digit by n's prefix.
Time: O(log n × |digits|) | Space: O(log n)
Count all valid numbers with
< m digits via k + k² + … + k^(m-1), then digit-DP the m-digit block bounded by n.
Time: O(log n × |digits|) | Space: O(log n)
Problem 4: Numbers With Repeated Digits (Leetcode:1012)#
Problem Statement
Given a positive integer n, return the number of positive integers ≤ n that have at least one repeated digit.
Example 1:
Input: n = 20
Output: 1
Explanation: Only 11 has a repeated digit.
Example 2:
Input: n = 100
Output: 10
Explanation: 11, 22, …, 99, 100.
Constraints:
1 <= n <= 10⁹
Code and Explanation
Answer =
n − (count of numbers ≤ n with all distinct digits). mask tracks used digits; skip any digit already in mask.
Time: O(log n × 10 × 2¹⁰) | Space: O(log n × 2¹⁰)
Numbers with all distinct digits: for length
L < m, first digit 1–9 and remaining L−1 from 9 unused digits (permutation). For length m, digit-DP the prefix bounded by n.
Time: O(log n × 10 × 2¹⁰) | Space: O(log n × 2¹⁰)
Probability DP#
Problem 1: Knight Probability in Chessboard (Leetcode:688)#
Problem Statement
On an n × n chessboard, a knight starts at (row, column) and makes exactly k moves. Each move is uniformly chosen among up to 8 L-shaped jumps. Return the probability the knight remains on the board after k moves.
Example 1:
Input: n = 3, k = 2, row = 0, column = 0
Output: 0.0625
Explanation: 2 of 32 equally likely paths stay on the board.
Example 2:
Input: n = 1, k = 0, row = 0, column = 0
Output: 1.0
Constraints:
1 <= n <= 250 <= k <= 1000 <= row, column <= n - 1
Code and Explanation
dp[r][c] = probability knight is at (r,c) after current number of moves. Each move spreads 1/8 of probability to reachable neighbors.
Time: O(k × n²) | Space: O(n²)
dfs(r,c,m) = probability of staying on board from (r,c) with m moves left. Same recurrence, computed lazily.
Time: O(k × n²) | Space: O(k × n²)
Problem 2: Soup Servings (Leetcode:808)#
Problem Statement
Two soups A and B start with n ml each. Each turn, one of four serve operations is chosen uniformly at random (each with probability 1/4). The first soup to empty (including simultaneous empty) determines the outcome. Return the probability that A empties before B, plus half the probability they empty together.
Example 1:
Input: n = 50
Output: 0.625
Example 2:
Input: n = 100
Output: 0.71875
Constraints:
0 <= n <= 10⁹
Code and Explanation
Scale
n by 25 ml per unit. dfs(a,b) = probability A wins from remaining (a,b). Base cases handle A-first, B-first, and tie. For large n, answer → 1 (empirical cutoff).
Time: O(m²) | Space: O(m²)
Fill table for all
(a,b) with a,b ≥ 0; clamp negative indices to base rows/columns (handled by iteration order from small to large).
Time: O(m²) | Space: O(m²)
Problem 3: New 21 Game (Leetcode:837)#
Problem Statement
Alice plays a game: she starts with 0 points and draws numbers 1..maxPts uniformly at random (each with probability 1/maxPts) until she stops at ≥ k points or reaches n. She stops as soon as points ≥ k. Return the probability her final score is ≤ n.
Example 1:
Input: n = 10, k = 1, maxPts = 1
Output: 1.0
Explanation: She immediately reaches k = 1.
Example 2:
Input: n = 6, k = 1, maxPts = 10
Output: 0.6
Example 3:
Input: n = 21, k = 17, maxPts = 10
Output: 0.73278
Constraints:
0 <= k <= n <= 10⁴1 <= maxPts <= 10⁴
Code and Explanation
dp[i] = probability of reaching exactly i points while still drawing (i < k). Each step averages the last maxPts reachable states via sliding window.
Time: O(n) | Space: O(n)
From each score
< k, spread probability to i + pts. Sum probabilities for final scores in [k, n].
Time: O(k × maxPts) | Space: O(n)
Problem 4: Dice Throw / Probability to Reach a Score (GeeksforGeeks)#
Problem Statement
Given d identical dice, each showing 1..6 uniformly, and a target sum x, count the number of ways to roll a total of exactly x. The probability of sum x is ways / 6^d.
Example 1:
Input: d = 2, x = 7
Output: 6
Explanation: (1,6), (2,5), (3,4), (4,3), (5,2), (6,1).
Example 2:
Input: d = 3, x = 8
Output: 21
Constraints:
1 <= d <= 30d <= x <= 6d
Code and Explanation
dp[i][s] = ways to get sum s with i dice. Each die adds face 1..6 to prior sums.
Time: O(d × x × 6) | Space: O(d × x)
Space-optimized version; probability is favorable outcomes divided by
6^d total outcomes.
Time: O(d × x × 6) | Space: O(x)
Problem 5: Probability of a Random Walk Reaching a Point (GeeksforGeeks)#
Problem Statement
A person starts at position 0 on a number line. At each step they move +1 or −1 with equal probability 1/2. After exactly n steps, return the probability of being at position x.
Example 1:
Input: n = 4, x = 0
Output: 0.375
Explanation: 6 of 16 paths return to 0: C(4,2)/2⁴ = 6/16.
Example 2:
Input: n = 3, x = 1
Output: 0.375
Explanation: C(3,2)/2³ = 3/8.
Constraints:
1 <= n <= 30|x| <= nandn − xis even (otherwise probability is 0)
Code and Explanation
dp[pos] = probability at position pos after current steps. Each step splits mass equally to neighbors.
Time: O(n²) | Space: O(n)
Need
right steps of +1 and left = n - right steps of −1. Count paths C(n, right) and divide by 2^n equally likely paths.
Time: O(n) | Space: O(1)
State Machine DP#
Problem 1: Best Time to Buy and Sell Stock (Leetcode:121)#
Problem Statement
You are given an array prices where prices[i] is the price of a stock on day i. You may buy once and sell once (sell after buy). Return the maximum profit. If no profit is possible, return 0.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy day 2 (price 1), sell day 5 (price 6).
Example 2:
Input: prices = [7,6,4,3,1]
Output: 0
Constraints:
1 <= prices.length <= 10⁵0 <= prices[i] <= 10⁴
Code and Explanation
State: cheapest buy price seen. Each day update profit if selling today.
Time: O(n) | Space: O(1)
hold = max cash after buying; sold = max after selling. One transaction caps transitions.
Time: O(n) | Space: O(1)
Problem 2: Best Time to Buy and Sell Stock II (Leetcode:122)#
Problem Statement
Given prices, you may complete as many transactions as you like (buy one and sell one share multiple times). You may not hold more than one share at a time. Return the maximum profit.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: (1,5)+(3,6) = 4+3 = 7.
Example 2:
Input: prices = [1,2,3,4,5]
Output: 4
Constraints:
1 <= prices.length <= 3 × 10⁴0 <= prices[i] <= 10⁴
Code and Explanation
Sum all positive day-over-day deltas — equivalent to buying every local min and selling every local max.
Time: O(n) | Space: O(1)
Problem 3: Best Time to Buy and Sell Stock III (Leetcode:123)#
Problem Statement
Given prices, find the maximum profit with at most two transactions. You may not hold more than one share at a time.
Example 1:
Input: prices = [3,3,5,0,0,3,1,4]
Output: 6
Explanation: (0,3)+(1,4) = 3+3 = 6.
Example 2:
Input: prices = [1,2,3,4,5]
Output: 4
Constraints:
1 <= prices.length <= 10⁵0 <= prices[i] <= 10⁵
Code and Explanation
buy1/sell1 = first transaction; buy2/sell2 = second after first completes. Chain states left to right.
Time: O(n) | Space: O(1)
dp[t][i][0/1] = max profit on day i with ≤ t transactions, not holding / holding stock.
Time: O(k × n) | Space: O(k × n)
Problem 4: Best Time to Buy and Sell Stock IV (Leetcode:188)#
Problem Statement
Given integer k and array prices, return the maximum profit with at most k transactions. Same rules as Stock III.
Example 1:
Input: k = 2, prices = [2,4,1]
Output: 2
Example 2:
Input: k = 2, prices = [3,2,6,5,0,3]
Output: 7
Constraints:
0 <= k <= 1001 <= prices.length <= 10000 <= prices[i] <= 1000
Code and Explanation
Same chained buy/sell arrays as Stock III, loop
t = 0..k−1. If k ≥ n/2, unlimited-trade greedy applies.
Time: O(k × n) | Space: O(k)
Rolling per-transaction hold/cash states updated each price.
Time: O(k × n) | Space: O(k)
Problem 5: Best Time to Buy and Sell Stock with Cooldown (Leetcode:309)#
Problem Statement
Given prices, maximize profit with unlimited transactions, but after you sell your stock, you cannot buy on the next day (one-day cooldown). You may not hold more than one share.
Example 1:
Input: prices = [1,2,3,0,2]
Output: 3
Explanation: buy 1 sell 2, cooldown, buy 0 sell 2.
Example 2:
Input: prices = [1]
Output: 0
Constraints:
1 <= prices.length <= 50000 <= prices[i] <= 1000
Code and Explanation
hold = holding stock; sold = just sold today; rest = not holding (cooldown cleared). Sell transitions from hold; rest takes max idle or post-sell cooldown.
Time: O(n) | Space: O(1)
Buy only from state two days ago (cooldown after sell on day
i−1).
Time: O(n) | Space: O(n)
Problem 6: Best Time to Buy and Sell Stock with Transaction Fee (Leetcode:714)#
Problem Statement
Given prices and integer fee, return the maximum profit with unlimited transactions. Each transaction pays fee when you sell. You may not hold more than one share.
Example 1:
Input: prices = [1,3,2,8,4,9], fee = 2
Output: 8
Example 2:
Input: prices = [1,3,7,5,10,3], fee = 3
Output: 6
Constraints:
1 <= prices.length <= 5 × 10⁴1 <= prices[i] <= 5 × 10⁴0 <= fee <= 5 × 10⁴
Code and Explanation
cash = max profit not holding; hold = max profit holding. Fee deducted on sell (hold + p - fee).
Time: O(n) | Space: O(1)
Paying fee on buy instead of sell gives identical optimal profit (shift by constant).
Time: O(n) | Space: O(1)
Problem 7: Binary Tree Cameras (Leetcode:968)#
Problem Statement
You are given the root of a binary tree. Install cameras on nodes to monitor all nodes. Each camera at a node monitors its node, parent, and immediate children. Return the minimum number of cameras needed.
Example 1:
Input: root = [0,0,null,0,0]
Output: 1
Example 2:
Input: root = [0,0,null,0,null,0,null,null,0]
Output: 2
Constraints:
- The number of nodes is in
[1, 1000].Node.val == 0
Code and Explanation
Post-order returns
(cameras, state): uncovered needs parent camera; child uncovered forces camera here; if any child has camera, this node is covered.
Time: O(n) | Space: O(h)
After processing children, if either child is uncovered, place a camera on the current node (covers node, both children, and parent). If root ends uncovered, add one more camera.
Time: O(n) | Space: O(h)