Skip to content

Commit 37f6bdf

Browse files
committed
Deep repo scan: 17 more missing classics — Burst Balloons, Target Sum, Rotate Array, Squares Of A Sorted Array, Find Pivot Index, Middle Of The Linked List, Palindrome Linked List, Design Hit Counter, Longest Happy String, Count And Say, Add Strings, Integer To English Words, Can Place Flowers, Word Break II, Maximum Erasure Value, Bus Routes, Minimum Genetic Mutations
1 parent d42073f commit 37f6bdf

28 files changed

Lines changed: 3960 additions & 0 deletions

‎CodingInterviewFightClub/src/SUMMARY.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
- [2.17 House Robber](ch02-dynamic-programming/house-robber.md)
5555
- [2.18 Maximum Subarray](ch02-dynamic-programming/maximum-subarray.md)
5656
- [2.19 Longest Increasing Subsequence](ch02-dynamic-programming/longest-increasing-subsequence.md)
57+
- [2.20 Burst Balloons](ch02-dynamic-programming/burst-balloons.md)
58+
- [2.21 Target Sum](ch02-dynamic-programming/target-sum.md)
5759

5860
- [3. Arrays, Two Pointers & Matrices](ch03-arrays/index.md)
5961
- [3.0 Pattern Primer: Two Pointers & The Sorted-Array Dance](ch03-arrays/pattern-primer.md)
@@ -69,6 +71,9 @@
6971
- [3.10 Product Of Array Except Self](ch03-arrays/product-of-array-except-self.md)
7072
- [3.11 Merge Sorted Array](ch03-arrays/merge-sorted-array.md)
7173
- [3.12 Set Matrix Zeroes](ch03-arrays/set-matrix-zeroes.md)
74+
- [3.13 Rotate Array](ch03-arrays/rotate-array.md)
75+
- [3.14 Squares Of A Sorted Array](ch03-arrays/squares-of-a-sorted-array.md)
76+
- [3.15 Find Pivot Index](ch03-arrays/find-pivot-index.md)
7277
- [2.12 Closest Subsequence Sum](ch02-dynamic-programming/closest-subsequence-sum.md)
7378

7479
- [4. Linked Lists](ch04-linked-lists/index.md)
@@ -80,6 +85,8 @@
8085
- [4.5 Linked List Cycle II](ch04-linked-lists/linked-list-cycle-ii.md)
8186
- [4.6 Find The Duplicate Number](ch04-linked-lists/find-the-duplicate-number.md)
8287
- [4.7 Add Two Numbers](ch04-linked-lists/add-two-numbers.md)
88+
- [4.8 Middle Of The Linked List](ch04-linked-lists/middle-of-the-linked-list.md)
89+
- [4.9 Palindrome Linked List](ch04-linked-lists/palindrome-linked-list.md)
8390

8491
- [5. Trees](ch05-trees/index.md)
8592
- [5.0 Pattern Primer: The Recursive Data Structure](ch05-trees/pattern-primer.md)
@@ -121,6 +128,8 @@
121128
- [7.6 Meeting Rooms III](ch07-heaps/meeting-rooms-iii.md)
122129
- [7.7 Single Threaded CPU](ch07-heaps/single-threaded-cpu.md)
123130
- [7.8 The Skyline Problem](ch07-heaps/the-skyline-problem.md)
131+
- [7.9 Design Hit Counter](ch07-heaps/design-hit-counter.md)
132+
- [7.10 Longest Happy String](ch07-heaps/longest-happy-string.md)
124133

125134
- [8. Stacks & Queues](ch08-stacks/index.md)
126135
- [8.0 Pattern Primer: LIFO, FIFO, and the Monotonic Stack](ch08-stacks/pattern-primer.md)
@@ -148,6 +157,8 @@
148157
- [9.9 Number Of Matching Subsequences](ch09-strings/number-of-matching-subsequences.md)
149158
- [9.10 Find The Index Of The First Occurrence (KMP)](ch09-strings/find-the-index-of-the-first-occurrence-kmp.md)
150159
- [9.11 Valid Palindrome](ch09-strings/valid-palindrome.md)
160+
- [9.12 Count And Say](ch09-strings/count-and-say.md)
161+
- [9.13 Add Strings](ch09-strings/add-strings.md)
151162

152163
- [10. Hash Tables & Sets](ch10-hash-tables/index.md)
153164
- [10.0 Pattern Primer: O(1) Lookup, Three Moves](ch10-hash-tables/pattern-primer.md)
@@ -164,6 +175,7 @@
164175
- [10.11 Subarray Sums Divisible By K](ch10-hash-tables/subarray-sums-divisible-by-k.md)
165176
- [10.12 Rank Transform Of An Array](ch10-hash-tables/rank-transform-of-an-array.md)
166177
- [10.13 Unique Number Of Occurrences](ch10-hash-tables/unique-number-of-occurrences.md)
178+
- [10.14 Integer To English Words](ch10-hash-tables/integer-to-english-words.md)
167179

168180
- [11. Greedy](ch11-greedy/index.md)
169181
- [11.0 Pattern Primer: The Local Choice, Defended](ch11-greedy/pattern-primer.md)
@@ -178,6 +190,7 @@
178190
- [11.9 Non-Overlapping Intervals](ch11-greedy/non-overlapping-intervals.md)
179191
- [11.10 Reorganize String](ch11-greedy/reorganize-string.md)
180192
- [11.11 Minimum Number Of Arrows To Burst Balloons](ch11-greedy/minimum-number-of-arrows-to-burst-balloons.md)
193+
- [11.12 Can Place Flowers](ch11-greedy/can-place-flowers.md)
181194

182195
- [12. Backtracking](ch12-backtracking/index.md)
183196
- [12.0 Pattern Primer: DFS With an Undo Button](ch12-backtracking/pattern-primer.md)
@@ -224,6 +237,7 @@
224237
- [15.6 Sliding Window Maximum](ch15-sliding-window/sliding-window-maximum.md)
225238
- [15.7 Max Consecutive Ones III](ch15-sliding-window/max-consecutive-ones-iii.md)
226239
- [15.8 Permutation In String](ch15-sliding-window/permutation-in-string.md)
240+
- [15.9 Maximum Erasure Value](ch15-sliding-window/maximum-erasure-value.md)
227241

228242
- [16. Bit Manipulation](ch16-bit-manipulation/index.md)
229243
- [16.0 Pattern Primer: The Bit Identities](ch16-bit-manipulation/pattern-primer.md)
@@ -249,6 +263,8 @@
249263
- [17.9 Reconstruct Itinerary](ch17-advanced-graphs/reconstruct-itinerary.md)
250264
- [17.10 Critical Connections In A Network](ch17-advanced-graphs/critical-connections-in-a-network.md)
251265
- [17.11 Walls And Gates](ch17-advanced-graphs/walls-and-gates.md)
266+
- [17.12 Bus Routes](ch17-advanced-graphs/bus-routes.md)
267+
- [17.13 Minimum Genetic Mutations](ch17-advanced-graphs/minimum-genetic-mutations.md)
252268

253269
- [18. Design & Caches](ch18-design-caches/index.md)
254270
- [18.0 Pattern Primer: Composing Structures](ch18-design-caches/pattern-primer.md)
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# 2.20 Burst Balloons
2+
3+
> **Source:** [`src/main/kotlin/array/dp/BurstBallonsClean.kt`](https://github.com/arpanpathak/AdvancedAlgorithmPatterns/blob/main/src/main/kotlin/array/dp/BurstBallonsClean.kt) (+ `BurstBaloons.kt`)
4+
> **Pattern:** interval DP with sentinels · **Core page**
5+
6+
## The Problem
7+
8+
Given `nums[i]` (balloon values), burst them one by one; bursting balloon `i` scores `nums[left] * nums[i] * nums[right]` (neighbors at that moment). Maximize total score.
9+
10+
- Constraints: $1 \le n \le 300$; values fit in `Int`.
11+
12+
## Examples
13+
14+
```
15+
Input: nums = [3,1,5,8] -> Output: 167 (burst order 1, 5, 3, 8)
16+
Input: nums = [1,5] -> Output: 10 (5 + 1·5·1... the padded view: burst 5 then 1)
17+
```
18+
19+
## Intuition — think in terms of the *last* balloon, padded with sentinel 1s
20+
21+
The classic trick: **work backwards**. Define `solve(left, right)` = max coins from bursting all balloons *between* `left` and `right` (exclusive), assuming `left` and `right` are **already-burst sentinels** that stay. Then for the *last* balloon `k` burst in that range, its neighbors are exactly `balloons[left]` and `balloons[right]` — the pad `[1] + nums + [1]` makes the boundary scoring uniform:
22+
23+
$$
24+
solve(left, right) = \max_{k \in (left, right)} \Big( A_{left} \cdot A_k \cdot A_{right} + solve(left, k) + solve(k, right) \Big)
25+
$$
26+
27+
**Why "last balloon" and not "first"?** If `k` is burst *last*, the sub-ranges `(left, k)` and `(k, right)` are independent — their balloons are gone before `k` pops, and `k`'s neighbors are the fixed sentinels. Burst-first thinking entangles the ranges; burst-last decomposes them. This is the [2.10](minimum-cost-to-cut-a-stick.md) interval-DP structure with the direction flipped.
28+
29+
**The repo's one-expression form** (`BurstBallonsClean.kt`):
30+
31+
```kotlin
32+
typealias State = Pair<Int, Int>
33+
34+
fun maxCoins(nums: IntArray): Int {
35+
val ballons = intArrayOf(1) + nums + 1 // sentinels
36+
val cache = mutableMapOf<State, Int>()
37+
38+
fun solve(left: Int, right: Int): Int = cache.getOrPut(left to right) {
39+
when {
40+
left > right -> 0 // empty range
41+
else -> (left..right).maxOf { k ->
42+
ballons[left - 1] * ballons[k] * ballons[right + 1] +
43+
solve(left, k - 1) + solve(k + 1, right)
44+
}
45+
}
46+
}
47+
return solve(1, ballons.size - 2)
48+
}
49+
```
50+
51+
**What's cool:** the whole recurrence is a `getOrPut` + `maxOf` (the [19.12-era](../ch02-dynamic-programming/pattern-primer.md) one-expression DP style, now in the main chapter). `solve(1, size - 2)` is "all real balloons, sentinels outside".
52+
53+
## Approach 1 — Brute force burst orders (n!)
54+
55+
Try every permutation: correct, factorial — the baseline.
56+
57+
## Approach 2 — Interval DP with sentinels (the repo's clean version, optimal)
58+
59+
```kotlin
60+
class BurstBallonsClean {
61+
fun maxCoins(nums: IntArray): Int {
62+
val ballons = intArrayOf(1) + nums + 1
63+
val cache = mutableMapOf<Pair<Int, Int>, Int>()
64+
65+
fun solve(left: Int, right: Int): Int = cache.getOrPut(left to right) {
66+
when {
67+
left > right -> 0
68+
else -> (left..right).maxOf { k ->
69+
ballons[left - 1] * ballons[k] * ballons[right + 1] +
70+
solve(left, k - 1) + solve(k + 1, right)
71+
}
72+
}
73+
}
74+
return solve(1, ballons.size - 2)
75+
}
76+
}
77+
```
78+
79+
```java
80+
import java.util.*;
81+
82+
public class BurstBalloons {
83+
/**
84+
* @param nums balloon values
85+
* @return max coins from bursting all balloons
86+
*/
87+
public int maxCoins(int[] nums) {
88+
int n = nums.length;
89+
int[] a = new int[n + 2];
90+
a[0] = a[n + 1] = 1; // sentinels
91+
for (int i = 0; i < n; i++) a[i + 1] = nums[i];
92+
93+
int[][] dp = new int[n + 2][n + 2];
94+
95+
for (int len = 1; len <= n; len++) { // window length
96+
for (int left = 1; left + len - 1 <= n; left++) {
97+
int right = left + len - 1;
98+
for (int k = left; k <= right; k++) {
99+
int score = a[left - 1] * a[k] * a[right + 1]
100+
+ dp[left][k - 1] + dp[k + 1][right];
101+
dp[left][right] = Math.max(dp[left][right], score);
102+
}
103+
}
104+
}
105+
return dp[1][n];
106+
}
107+
}
108+
```
109+
110+
```cpp
111+
#include <vector>
112+
#include <algorithm>
113+
114+
class BurstBalloons {
115+
public:
116+
/**
117+
* @param nums balloon values
118+
* @return max coins from bursting all balloons
119+
*/
120+
int maxCoins(std::vector<int>& nums) {
121+
int n = nums.size();
122+
std::vector<int> a(n + 2, 1); // sentinels
123+
for (int i = 0; i < n; i++) a[i + 1] = nums[i];
124+
125+
std::vector<std::vector<int>> dp(n + 2, std::vector<int>(n + 2, 0));
126+
127+
for (int len = 1; len <= n; len++) {
128+
for (int left = 1; left + len - 1 <= n; left++) {
129+
int right = left + len - 1;
130+
for (int k = left; k <= right; k++) {
131+
dp[left][right] = std::max(dp[left][right],
132+
a[left - 1] * a[k] * a[right + 1] + dp[left][k - 1] + dp[k + 1][right]);
133+
}
134+
}
135+
}
136+
return dp[1][n];
137+
}
138+
};
139+
```
140+
141+
```python
142+
def max_coins(nums: list[int]) -> int:
143+
"""
144+
@param nums: balloon values
145+
@return: max coins from bursting all balloons
146+
"""
147+
a = [1] + nums + [1] # sentinels
148+
n = len(nums)
149+
dp = [[0] * (n + 2) for _ in range(n + 2)]
150+
151+
for length in range(1, n + 1): # window length
152+
for left in range(1, n - length + 2):
153+
right = left + length - 1
154+
for k in range(left, right + 1):
155+
score = a[left - 1] * a[k] * a[right + 1] + dp[left][k - 1] + dp[k + 1][right]
156+
dp[left][right] = max(dp[left][right], score)
157+
return dp[1][n]
158+
```
159+
160+
```rust
161+
impl Solution {
162+
/// @param nums balloon values
163+
/// @return max coins from bursting all balloons
164+
pub fn max_coins(nums: Vec<i32>) -> i32 {
165+
let n = nums.len();
166+
let mut a = vec![1; n + 2]; // sentinels
167+
for (i, &v) in nums.iter().enumerate() { a[i + 1] = v; }
168+
169+
let mut dp = vec![vec![0i32; n + 2]; n + 2];
170+
171+
for len in 1..=n {
172+
for left in 1..=(n - len + 1) {
173+
let right = left + len - 1;
174+
for k in left..=right {
175+
dp[left][right] = dp[left][right].max(
176+
a[left - 1] * a[k] * a[right + 1] + dp[left][k - 1] + dp[k + 1][right]);
177+
}
178+
}
179+
}
180+
dp[1][n]
181+
}
182+
}
183+
```
184+
185+
## Dry run
186+
187+
**Input:** `nums = [3,1,5,8]`. Padded: `a = [1,3,1,5,8,1]`.
188+
189+
```
190+
length-1 windows: dp[1][1] = a[0]*a[1]*a[2] = 1*3*1 = 3. (burst 3 alone: 3)
191+
dp[2][2] = a[1]*a[2]*a[3] = 3*1*5 = 15. dp[3][3] = 1*5*8 = 40. dp[4][4] = 5*8*1 = 40.
192+
length-2: dp[1][2] = max(k=1: a0*a1*a3 + dp[2][2] = 1*3*5+15 = 30,
193+
k=2: a0*a2*a3 + dp[1][1] = 1*1*5+3 = 8) = 30.
194+
dp[2][3] = max(k=2: a1*a2*a4 + dp[3][3] = 3*1*8+40 = 64,
195+
k=3: a1*a3*a4 + dp[2][2] = 3*5*8+15 = 135) = 135.
196+
dp[3][4] = max(k=3: a2*a3*a5 + dp[4][4] = 1*5*1+40 = 45,
197+
k=4: a2*a4*a5 + dp[3][3] = 1*8*1+40 = 48) = 48.
198+
length-3: dp[1][3] = max(k=1: a0*a1*a4 + dp[2][3] = 1*3*8+135 = 159,
199+
k=2: a0*a2*a4 + dp[1][1]+dp[3][3] = 1*1*8+3+40 = 51,
200+
k=3: a0*a3*a4 + dp[1][2] = 1*5*8+30 = 70) = 159.
201+
length-4: dp[1][4] = max(k=1: a0*a1*a5 + dp[2][4] = 1*3*1+48 = 51,
202+
k=2: a0*a2*a5 + dp[1][1]+dp[3][4] = 1*1*1+3+48 = 52,
203+
k=3: a0*a3*a5 + dp[1][2]+dp[4][4] = 1*5*1+30+40 = 75,
204+
k=4: a0*a4*a5 + dp[1][3] = 1*8*1+159 = 167) = 167.
205+
206+
Output: 167 ✓
207+
```
208+
209+
The last-balloon reading of the winning `k=4` (burst 8 last): the 8's neighbors are the sentinels `a[0]` and `a[5]` (both 1) → 8 points, plus the optimal `dp[1][3] = 159` from the remaining three — the ranges decompose exactly because 8 goes last.
210+
211+
## Complexity
212+
213+
**Time.** All (left, k, right) triples:
214+
215+
$$
216+
T(n) = O(n^3)
217+
$$
218+
219+
**Space.** The interval table:
220+
221+
$$
222+
S(n) = O(n^2)
223+
$$
224+
225+
## Variants & follow-ups
226+
227+
- **Minimum Cost To Cut A Stick** ([2.10](minimum-cost-to-cut-a-stick.md)) — the interval-DP sibling (min instead of max, cut-first instead of burst-last).
228+
- **Stone Game** — the zero-sum interval DP (now a section on the [2.10](minimum-cost-to-cut-a-stick.md) page).
229+
- **Interview follow-up:** "Why pad with 1s?" Without sentinels, the *first* and *last* bursts have only one neighbor — a special case. The `[1] + nums + [1]` pad makes every burst uniformly `left × k × right`, so the recurrence needs no boundary branches.

‎CodingInterviewFightClub/src/ch02-dynamic-programming/index.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
| 2.17 | House Robber | include/exclude two-variable DP | $O(n)$ | [→](house-robber.md) |
3131
| 2.18 | Maximum Subarray | Kadane best-ending-here | $O(n)$ | [→](maximum-subarray.md) |
3232
| 2.19 | Longest Increasing Subsequence | dp over all previous | $O(n^2)$ | [→](longest-increasing-subsequence.md) |
33+
| 2.20 | Burst Balloons | interval DP + sentinels | $O(n^3)$ | [→](burst-balloons.md) |
34+
| 2.21 | Target Sum | (index, sum) memo | $O(nS)$ | [→](target-sum.md) |
3335
## Reading order
3436

3537
2.2 and 2.3 first — they're the *ur-examples* of the state-shape `dp[i][j]`. Then 2.1 (same table, different recurrence), then the knapsack family (2.4–2.6) which is the most frequently re-appearing pattern in real interviews, then the interval DPs (2.10, 2.11), then the gyms (2.8, 2.9, 2.13). End with 2.12 which is the *anti-DP* — it proves you know when **not** to reach for a DP table.

0 commit comments

Comments
 (0)