戳气球
有 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
思路
考虑最后一个戳破的气球,这个气球的位置可以把整个气球数组分成两部分。
注意是最后一个,不是第一个,之前一直没转过弯来。
利用动态规划思路:
动态规划数组:
DP[k][h]:nums[k...h]能戳破气球的最大值
递推关系:
取k<m<h,nums[m]假设是最后一个戳破的气球
则DP[k][h] =
for (m = k+1...h)
max(DP[k][m] + DP[m][h] + nums[k] * nums[m] * nums[h]);
初始值:
需要扩展nums,数组长+2,头和尾分别加入1
DP[k][h]:
当k + 1 = h 或 k = h时,为0;
当k + 2 = h 时,为 nums[k] * nums[k+1] * nums[k+2];
1 public class Solution{
2 public int maxCoins(int[] nums) {
3 //DP: the result depends on the last burst balloon, which seprate the array into 2 subarray.
4 // DP: by adding 1 to head and tail, DP[i,i] = 0 and DP[i,i+2] = num[i] * num[i+1] * num[i+2]
5 int n = nums.length+2;
6 int[] newnums = new int[n];
7 for (int i = 0;i < n - 2; i++){
8 newnums[i+1] = nums[i];
9 }
10 newnums[0] = newnums[n - 1] = 1;
11 int[][] DP = new int[n][n];
12 for (int k = 2; k < n; k++){
13 for (int l = 0; l + k < n; l++){
14 int h = l + k;
15 for (int m = l + 1; m < h; m++){
16 DP[l][h] = Math.max(DP[l][h],newnums[l] * newnums[m] * newnums[h] + DP[l][m] + DP[m][h]);
17 }
18 }
19 }
20 return DP[0][n - 1];
21 }
22 }
来源:oschina
链接:https://my.oschina.net/u/4270565/blog/3685353