leetcode 312.戳气球
题目:
有 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
分析:
我是看了别人的代码才懂的,这段代码是别人的,我自己后来写了一份,这里就贴上别人的代码,是在评论区里的。
首先他的代码中已经给出了一定的解释,先去看一下然后再看我的解释。
有一些朋友可能会不懂这个动态方程为什么这么写,假如现在有一行气球,我们定义最后戳破第k个气球可以得到最大的收益,首先我们要明白他注释中的 i 和 j 位置不一定是气球!也有可能是边界,也就是最后剩下的不是3个气球,而是一个气球,只是他的左右两边已经事先填充了两个不会被戳破的“气球”了。
最后我们就可以得到了这个动态转移方程,每当加进来一个气球,我们就计算戳破第k个气球可以得到的收益,并且循环计算出最大的收益。当把最后一个气球给放入的时候,我们用原先计算的最大值就可以推导出最后的最大收益了。
1 class Solution { 2 public int maxCoins(int[] nums) { 3 int[] balls = new int[nums.length+2]; 4 balls[0] = 1; 5 balls[balls.length - 1] = 1; 6 int[][] coins = new int[balls.length][balls.length]; 7 for(int i = 0; i < nums.length; i++) 8 { 9 balls[i+1] = nums[i]; 10 } 11 12 for(int j = 2; j < balls.length; j++) 13 { 14 for(int i = j - 2; i >= 0; i--) 15 { 16 for(int k = j -1; k > i; k--) 17 { 18 /* 这个里面的coins[i][k] + balls[i]*balls[k]*balls[j] + coins[k][j] 19 是最大的可以这样理解:以k分割(为什么会有k,因为无论怎么戳,最后剩三个 20 的时候,一定是i,j和另一个,另一个就是k,那么要总的结果最大,那么要k 21 两边的值都取最 22 大,两边值最大是什么:即coins[i][k],coins[k][j],先戳两边的把两个最 23 大找出来,最后左右两边剩什么呢,正是最左边的balls[i]和最右边的balls[j], 24 最后处理k处的即balls[i]*balls[k]*balls[j] 25 */ 26 coins[i][j] = Math.max(coins[i][j], coins[i][k] 27 + balls[i]*balls[k]*balls[j] + coins[k][j]); 28 } 29 } 30 } 31 for(int n=0;n<balls.length;++n) { 32 System.out.println(); 33 for(int m=0;m<balls.length;++m) 34 System.out.print(coins[n][m]+" "); 35 } 36 return coins[0][balls.length - 1]; 37 } 38 }