312. 戳气球
20200719
难度:困难
题目描述
有 n 个气球,编号为0 到 n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。如果你戳破气球 i ,就可以获得 nums[left] * nums[i] * nums[right] 个硬币。 这里的 left 和 right 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球。
求所能获得硬币的最大数量。
说明:
- 你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。
- 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
示例:
输入: [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
Solution
动态规划 区间dp
-
状态:
dp[i][j]
代表戳破[i,j]
的气球所能获得硬币的最大数量。 -
状态转移:枚举区间——左端点——最后一个戳破的气球
dp[i][j] = Math.max(dp[i][j], dp[i][k-1] + dp[k+1][j] + expand[i-1] * expand[k] * expand[j+1]);
class Solution {
public int maxCoins(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int n = nums.length;
int[][] dp = new int[n+2][n+2];
//扩展nums[-1] = nums[n] = 1
int[] expand = new int[n+2];
expand[0] = 1;
expand[n+1] = 1;
for(int i = 0; i < n; i++){
expand[i+1] = nums[i];
}
for(int len = 1; len <= n; len++){//枚举区间
for(int i = 1; i + len - 1 <= n; i++){//左端点
int j = i + len - 1;//右端点
for(int k = i; k <= j; k++){//枚举最后一个戳破的气球
dp[i][j] = Math.max(dp[i][j], dp[i][k-1] + dp[k+1][j] + expand[i-1] * expand[k] * expand[j+1]);
}
}
}
return dp[1][n];
}
}
欢迎关注公众号:GitKid,暂时每日分享LeetCode题解,在不断地学习中,公众号内容也在不断充实,欢迎扫码关注