有 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
class Solution { public int maxCoins(int[] nums) { int len = nums.length; int[] langarr = new int[len+2]; langarr[0] = 1; for (int i = 0, j = 1; i < len; i++, j++) langarr[j] = nums[i]; len = langarr.length; int[][] dp = new int[len][len]; langarr[len-1] = 1; for (int i = 2; i < len; i++) { for (int j = 0; j+i < len; j++) { for (int k = j+1; k < j+i; k++) { dp[j][j+i] = Math.max(dp[j][j+i], dp[j][k]+dp[k][j+i]+langarr[j]*langarr[k]*langarr[j+i]); } } } return dp[0][len-1]; } }
dp[i][j]的含义是 第i个气球到第j个气球(不包含i,j) ,最好的扎法能得多少分。
dp[j][j+i] = Math.max(dp[j][j+i], dp[j][k]+dp[k][j+i]+langarr[j]*langarr[k]*langarr[j+i]);
以上是最精华的递推公式,这种属于分治思想,分治的动态规划题 dp为二维的时候,从短的长度到长的长度去渗透,
k的含义是,假设k是最后一个扎破的气球, 这个想法最关键(自己想到了分治,但是总是感觉左右会有依赖没法分),也是这道题最难想到的点,最后一个扎破的气球的左边和右边是完全没有依赖关系的,可以分别运算的部分。
如果k是最后一个扎破的,那么最后一次的得分也可以得出。