【问题描述】[困难]
【解答思路】
1. 记忆化搜索
时间复杂度:O(n^3) 空间复杂度:O(n^2)
class Solution {public int[][] rec;public int[] val;public int maxCoins(int[] nums) {int n = nums.length;val = new int[n + 2];for (int i = 1; i <= n; i++) {val[i] = nums[i - 1];}val[0] = val[n + 1] = 1;rec = new int[n + 2][n + 2];for (int i = 0; i <= n + 1; i++) {Arrays.fill(rec[i], -1);}return solve(0, n + 1);}public int solve(int left, int right) {if (left >= right - 1) {return 0;}if (rec[left][right] != -1) {return rec[left][right];}for (int i = left + 1; i < right; i++) {int sum = val[left] * val[i] * val[right];sum += solve(left, i) + solve(i, right);rec[left][right] = Math.max(rec[left][right], sum);}return rec[left][right];}
}
2. 动态规划
第 1 步:设计状态
dp[i][j] = x 表示,戳破气球 i 和气球 j 之间(开区间,不包括 i 和 j)的所有气球,可以获得的最高分数为 x。
第 2 步:状态转移方程
i>j之间没有气球 均为0
第 3 步:考虑初始化
base case 已经都被初始化为 0
int[][] dp = new int[n + 2][n + 2];
第 4 步:考虑输出
dp[0][n+1] )
斜着遍历较难实现,一般从上到下实现
时间复杂度:O(N^3) 空间复杂度:O(N^2)
class Solution {public int maxCoins(int[] nums) {int n = nums.length;int[][] rec = new int[n + 2][n + 2];int[] val = new int[n + 2];val[0] = val[n + 1] = 1;for (int i = 1; i <= n; i++) {val[i] = nums[i - 1];}for (int i = n - 1; i >= 0; i--) {for (int j = i + 2; j <= n + 1; j++) {for (int k = i + 1; k < j; k++) {int sum = val[i] * val[k] * val[j];sum += rec[i][k] + rec[k][j];rec[i][j] = Math.max(rec[i][j], sum);}}}return rec[0][n + 1];}
}
【总结】
1. 动态规划流程
第 1 步:设计状态
第 2 步:状态转移方程
第 3 步:考虑初始化
第 4 步:考虑输出
第 5 步:考虑是否可以状态压缩
2.关于「状态」的穷举,最重要的一点就是:状态转移所依赖的状态必须被提前计算出来。 通过 初始状态的base case 和最终状态 推导出 i,j 的遍历方向,保证正确的状态转移
3.关键在于 dp 数组的定义,需要避免子问题互相影响,所以我们反向思考,将 dp[i][j] 的定义设为开区间,考虑最后戳破的气球是哪一个,以此构建了状态转移方程。
4. 回溯算法伪代码以及套路
回溯算法超时 需要结合记忆化搜索
int res = Integer.MIN_VALUE;
/* 输入一组气球,返回戳破它们获得的最大分数 */
int maxCoins(int[] nums) {backtrack(nums, 0); return res;
}
/* 回溯算法的伪码解法 */
void backtrack(int[] nums, int socre) {if (nums 为空) {res = max(res, score);return;}for (int i = 0; i < nums.length; i++) {int point = nums[i-1] * nums[i] * nums[i+1];int temp = nums[i];// 做选择在 nums 中删除元素 nums[i]// 递归回溯backtrack(nums, score + point);// 撤销选择将 temp 还原到 nums[i]}
}
根据题意定义出口(可选)
for 选择 in 选择列表:# 做选择将该选择从选择列表移除路径.add(选择)backtrack(路径, 选择列表)# 撤销选择路径.remove(选择)将该选择再加入选择列表
https://labuladong.gitbook.io/algo/di-ling-zhang-bi-du-xi-lie/hui-su-suan-fa-xiang-jie-xiu-ding-ban
参考链接:https://leetcode-cn.com/problems/burst-balloons/solution/dong-tai-gui-hua-tao-lu-jie-jue-chuo-qi-qiu-wen-ti/
转载链接:https://leetcode-cn.com/problems/burst-balloons/solution/chuo-qi-qiu-by-leetcode-solution/