戳气球问题

312.戳气球

遇到求最值的算法问题,首先要思考的就是:如何穷举出所有可能的结果?

穷举主要有两种算法,就是回溯算法动态规划,前者就是暴力穷举,而后者是根据状态转移方程推导「状态」。

如何将戳气球问题转化成回溯算法呢?其实就是想穷举戳气球的顺序,不同的戳气球顺序可能得到不同的分数,把所有可能的分数中最高的那个找出来。

回溯算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int res = Integer.MIN_VALUE;
/* 输入一组气球,返回戳破它们获得的最大分数 */
int maxCoins(int[] nums) {
backtrack(nums, 0);
return res;
}
/* 回溯算法的伪码解法 */
void backtrack(int[] nums, int socre) {
if (nums 为空) {
res = Math.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]
}
}

动态规划

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int maxCoins(int[] nums) {
int n = nums.length;
// 添加两侧的虚拟气球
int[] points = new int[n + 2];
points[0] = points[n + 1] = 1;
for (int i = 1; i <= n; i++) {
points[i] = nums[i - 1];
}
// base case 已经都被初始化为 0
int[][] dp = new int[n + 2][n + 2];
// 开始状态转移
// i 应该从下往上
for (int i = n; i >= 0; i--) {
// j 应该从左往右
for (int j = i + 1; j < n + 2; j++) {
// 最后戳破的气球是哪个?
for (int k = i + 1; k < j; k++) {
// 择优做选择
dp[i][j] = Math.max(
dp[i][j],
dp[i][k] + dp[k][j] + points[i]*points[j]*points[k]
);
}
}
}
return dp[0][n + 1];
}
坚持原创技术分享,您的支持将鼓励我继续创作!