leetcode 戳气球
有 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,一个状态不行定义两个状态。正推不行反推,从后往前想,枚举最后一个戳破的气球,定义状态dp[i][j]为i到j的所有气球都戳破的最大价值。dp[i][j] = max(dp[i+1][k]+dp[k+1][j]+ input[i-1] * input[k] * input[j+1]);
k为i到j,注意加的价值为位置k气球的价值,以及i-1和j+1位置气球的价值。
class Solution { public int maxCoins(int[] nums) { int n = nums.length; if(n==0) return 0; if(n==1) return nums[0]; int[][] dp = new int[n][n]; dp[0][0] = nums[0] * nums[1]; dp[n - 1][n - 1] = nums[n - 2] * nums[n - 1]; for (int i = 1; i < n - 1; i++) { dp[i][i] = nums[i - 1] * nums[i] * nums[i + 1]; } for (int t = 1; t < n; t++) { for (int i = 0; i < n; i++) { int j = i + t; if (j < n) { for (int k = i ; k <= j ; k++) { int left = k-1 >= i ? dp[i][k-1]:0; int right = k+1 <= j ? dp[k+1][j]:0; int p, q, r; if (i == 0) p = 1; else p = nums[i - 1]; if (j == n - 1) r = 1; else r = nums[j + 1]; q = nums[k]; dp[i][j] = Math.max(dp[i][j], left +right + p * q * r); } } } } // for (int i = 0; i < n; i++) { // for (int j = 0; j < n; j++) { // System.out.print(dp[i][j] + " "); // } // System.out.println(); // } // System.out.println(dp[0][n - 1]); return dp[0][n-1]; } }