LeetCode-312. 戳气球
题目来源
题目详情
有 n
个气球,编号为0
到 n - 1
,每个气球上都标有一个数字,这些数字存在数组 nums
中。
现在要求你戳破所有的气球。戳破第 i
个气球,你可以获得 nums[i - 1] * nums[i] * nums[i + 1]
枚硬币。 这里的 i - 1
和 i + 1
代表和 i
相邻的两个气球的序号。如果 i - 1
或 i + 1
超出了数组的边界,那么就当它是一个数字为 1
的气球。
求所能获得硬币的最大数量。
示例 1:
输入: nums = [3,1,5,8]
输出: 167
解释:
nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
示例 2:
输入: nums = [1,5]
输出: 10
提示:
n == nums.length
1 <= n <= 500
0 <= nums[i] <= 100
题解分析
- 本题的实现是使用动态规划的思想,因为题目的描述出现了最大数量等词眼,而且题目是数组的形式出现,非常符合动态规划题目的形态。
- 要用动态规划就要思考子问题是什么,这里肯定不是从前i个元素的角度思考问题,因为戳气球涉及到相邻元素的相互影响。
- 与5. 最长回文子串题目类似,这里需要考虑不同长度的子数组作为子问题。我们可以设置假设 dp[i][j] 表示开区间 (i,j) 内你能拿到的最多金币,并假设(i, j)区间中气球只剩最后一个,编号为k(k两边的气球都被戳爆了)。
- 状态转移方程如下:\(dp[i][j] = max(dp[i][j], dp[i][k] + nums[i] * nums[k] * nums[j] + dp[k][j])\)。
class Solution {
public int maxCoins(int[] nums) {
int n = nums.length;
int[] ball = new int[n+2];
ball[0] = 1;
ball[n+1] = 1;
System.arraycopy(nums, 0, ball, 1, n);
int[][] dp = new int[n+2][n+2];
for(int len = 3; len <= n + 2; len++){
for(int i=0; i<= n + 2 - len; i++){
int j = i+ len - 1;
dp[i][j] = 0;
for(int k=i+1; k<j; k++){
dp[i][j] = Math.max(dp[i][k] +dp[k][j] + ball[i] * ball[k] * ball[j], dp[i][j]);
}
}
}
return dp[0][n+1];
}
}
结果展示
Either Excellent or Rusty