题目
示例
思路:动态规划
-
在数组首尾增加元素1。
-
状态:dp[i][j]表示(i,j)之间气球全部爆炸产生的最大收益,i,j不爆炸。
-
初始化:dp[i][j] = 0;
-
状态转移方程:
dp[i][j] = Math.max(dp[i][j],nums[i]*nums[k]*nums[j]+dp[i][k]+dp[k][j]);
nums[i]*nums[k]*nums[j]+dp[i][k]+dp[k][j]
表示nums[k]最后爆炸,dp[i][j]可以获得的最大收益。 -
三层循环,最外层是窗口大小,窗口逐渐增大,从窗口大小为3,逐渐增大到数组长度。
for(int k = 2;k < n;k++)
第二层是窗口起点,每次都是从0开始,增大到与末尾节点的距离刚好是窗口大小for(int left = 0;left < n-k;left++)
第三层是最后爆炸的气球位置,窗口的右边界为左边界+k,气球位置在左右边界开区间内for(int boom = left + 1; boom < right;boom++)
-
输出dp[0][n-1]
具体代码
class Solution {
public int maxCoins(int[] nums) {
int newNums[] = new int[nums.length+2];
int n = 1;
for(int x : nums){
if(x > 0){
//如果有值为0,则乘积为0,没有贡献,所以无需加入新数组中
newNums[n++] = x;
}
}
//在数组首尾添加1.
newNums[0] = newNums[n++] = 1;
//dp[i][j]表示(i,j)内所有气球爆炸得到的最大值,i、j不爆炸。
int dp[][] = new int[n][n];
for(int k = 2;k < n;k++){
for(int left = 0;left < n - k;left++){
int right = left + k;
for(int i = left + 1;i < right;i++){
//(left,right)之间的最大值为Max(前一个dp[left][right],让nums[i]最后爆炸的结果)
dp[left][right] = Math.max(dp[left][right],newNums[left]*newNums[i]*newNums[right]+dp[left][i]+dp[i][right]);
}
}
}
return dp[0][n-1];
}
}
时间复杂度:O(N^3)
空间复杂度:O(N^2)
参考资料
leetcode题解