You are given n balloons, indexed from 0 to n - 1. Each balloon is painted with a number on it represented by an array nums. You are asked to burst all the balloons.
If you burst the ith balloon, you will get nums[i - 1] * nums[i] * nums[i + 1] coins. If i - 1 or i + 1 goes out of bounds of the array, then treat it as if there is a balloon with a 1 painted on it.
Return the maximum coins you can collect by bursting the balloons wisely.
Input: nums =[1,5]Output: 10Note: (1) You may imagine nums[-1]= nums[n]=1. They are not real therefore you can not burst them.(2)0≤ n ≤500,0≤ nums[i]≤100
The brute-force (backtracking) approach tries every possible order of bursting balloons. For each step, it chooses a balloon to burst, calculates the coins gained, and recursively solves the subproblem for the remaining balloons. Since the coins gained depend on the immediate neighbors, we must update the list after each burst. This explores all possible sequences, ensuring we find the maximum.
We have n balloons to burst, which mean we have n steps in the game. In the i th step we have n-i balloons to burst, i = 0~n-1.
The naive recursive approach explores every possible order of bursting balloons. For each step, it tries bursting each balloon, calculates the coins gained, and recursively solves the subproblem for the remaining balloons. Since the coins depend on the immediate neighbors, the list must be updated after each burst. This method guarantees the correct answer but is highly inefficient for large inputs.
Instead of bursting balloons in any order, we think in reverse: for any subarray, consider which balloon is the last to burst. Bursting the last balloon in a subarray splits the problem into two independent subproblems (left and right of the last balloon), making it suitable for divide and conquer with memoization.
Instead of solving the problem recursively, we use dynamic programming to build up solutions for smaller subarrays and use them to solve larger ones. By considering all possible last balloons to burst in each subarray, we can fill a DP table iteratively.
publicclassSolution {
publicintmaxCoins(int[] nums) {
int n = numslength;
int[] updatedNums =newint[n + 2];
int len = 1;
for (int x : nums) {
updatedNums[len++]= x;
}
updatedNums[0]= updatedNums[len++]= 1;
int[][] dp =newint[len][len];
for (int k = 2; k < len; ++k) {
for (int left = 0; left < len - k; ++left) {
int right = left + k;
for (int i = left + 1; i < right; ++i) {
dp[left][right]= Math.max(
dp[left][right],
nums[left]* updatedNums[i]* updatedNums[right]+ dp[left][i]+ dp[i][right] );
}
}
}
return dp[0][len - 1];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
classSolution:
defmaxCoins(self, nums: list[int]) -> int:
nums = [1] + nums + [1]
n = len(nums)
dp = [[0] * n for _ in range(n)]
for k in range(2, n):
for left in range(0, n - k):
right = left + k
for i in range(left +1, right):
dp[left][right] = max(
dp[left][right],
nums[left] * nums[i] * nums[right] + dp[left][i] + dp[i][right]
)
return dp[0][n -1]