问题


例子

思路
回溯时间太久【第一次有n个选择,第二次有n-1个选择,时间为O(n!)】
动态规划【有最字】+分治
区间[i, j] 戳破的气球为k。
k戳破后,区间变成了[i, k) 和(k, j],即[i, i+1, … k-1, k+1, …j],那么k+1啥时候戳破对[i, k)的结果有影响,如果先戳破k-1,再戳破k+1,k-1的右边是k+1,计算时[k-2]*[k-1]*[k+1],如果先戳破,(k, j]中的k+1,再戳破[i, k)中的k-1,此时k-1右边的变成了k+2,计算时[k-2]*[k-1]*[k+2]
,即左右两边区间的计算产生了依赖。
如何不产生依赖呢?气球k,放在最后戳爆它。
k为区间[i, j]间最后一个戳爆的气球,它把[i, j]分为了[i, k-1]和[k+1, j]两个区间,可分别求出
-
方法1
状态转移方程 dp[i][j]为[i,j]区间的最大值dp[i][j]=max(dp[i][k−1]+dp[k+1][j]+arr[i−1]∗arr[k]∗arr[j+1]) i<=k<=j 状态转移方程~~ dp[i][j]为[i,j]区间的最大值\\ dp[i][j]=max(dp[i][k-1]+dp[k+1][j]+arr[i-1]*arr[k]*arr[j+1]) ~~i<=k<=j 状态转移方程 dp[i][j]为[i,j]区间的最大值dp[i][j]=max(dp[i][k−1]+dp[k+1][j]+arr[i−1]∗arr[k]∗arr[j+1]) i<=k<=j -
方法2
$$$$
代码
//方法1 自顶向下
class Solution {
public int maxCoins(int[] nums) {
//创建虚拟边界
int[] arr = new int[nums.length+2];
System.arraycopy(nums,0,arr,1,nums.length);
arr[0]=1;
arr[arr.length-1]=1;
int[][] dp = new int[arr.length][arr.length];
return get(arr,1,arr.length-2,dp);
}
public int get(int[] arr,int i,int j, int[][] dp) {
if(i>j) return 0;
if(dp[i][j]>0) return dp[i][j];
int max = 0;
for(int k=i; k<=j; k++) {
max = Math.max(max, arr[i-1]*arr[k]*arr[j+1]+get(arr, i,k-1,dp)+get(arr,k+1,j,dp));
}
dp[i][j]=max;
return max;
}
}
//方法2 自下而上
class Solution {
public int maxCoins(int[] nums) {
int n = nums.length;
//创建虚拟边界
int[] arr = new int[n+2];
System.arraycopy(nums,0,arr,1,n);
arr[0]=1;
arr[n+1]=1;
int[][] dp = new int[n+2][n+2];
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], arr[i-1]*arr[k]*arr[j+1]+dp[i][k-1]+dp[k+1][j]);
}
}
}
return dp[1][n];
}

本文探讨了著名的气球戳破问题,通过动态规划方法寻找戳破一系列气球以获得最大分数的最优策略。文章详细解析了状态转移方程,展示了如何避免回溯过程中的依赖性,并提供了两种实现方式的代码示例。
893

被折叠的 条评论
为什么被折叠?



