0312. Burst Balloons (H)

Burst Balloons (H)

题目

Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.java

Find the maximum coins you can collect by bursting the balloons wisely.code

Note:游戏

  • You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
  • 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100

Example:get

Input: [3,1,5,8]
Output: 167 
Explanation: 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

题意

打气球游戏。每一个气球有对应的分值,打爆一个气球i,能获得的积分为气球i、气球i-一、气球i+1积分的乘积。要求计算可以得到的最大积分。it

思路

动态规划问题。dp[left, right]表示打爆从left到right全部气球能获得的最大积分。每一次咱们在[left, right]这个区间中选择一个i,表明该区间中最后一个被打爆的气球,那么能够获得递推关系式:io

\[dp[left,\ right]=\max_{left \le i \le right}(dp[left,\ i-1]+dp[i+1,\ right]+nums[left-1]*nums[i]*nums[right+1]) \]


代码实现

Java

记忆化搜索

class Solution {
    public int maxCoins(int[] nums) {
        int[][] memo = new int[nums.length][nums.length];
        for (int i = 0; i < nums.length; i++) {
            Arrays.fill(memo[i], -1);
        }
        return dfs(nums, 0, nums.length - 1, memo);
    }

    private int dfs(int[] nums, int left, int right, int[][] memo) {
        if (right < left) {
            return 0;
        }
        if (memo[left][right] != -1) {
            return memo[left][right];
        }
        int max = 0;
        for (int i = left; i <= right; i++) {
            int x = dfs(nums, left, i - 1, memo)
                    + dfs(nums, i + 1, right, memo)
                    + nums[i] * (left == 0 ? 1 : nums[left - 1]) * (right == nums.length - 1 ? 1 : nums[right + 1]);
            max = Math.max(max, x);
        }
        memo[left][right] = max;
        return max;
    }
}

动态规划

class Solution {
    public int maxCoins(int[] nums) {
        if (nums.length == 0) {
            return 0;
        }

        int[][] dp = new int[nums.length][nums.length];
        for (int right = 0; right < nums.length; right++) {
            for (int left = right; left >= 0; left--) {
                for (int i = left; i <= right; i++) {
                    int leftMax = i == left ? 0 : dp[left][i - 1];
                    int rightMax = i == right ? 0 : dp[i + 1][right];
                    int last = nums[i] * (left == 0 ? 1 : nums[left - 1]) * (right == nums.length - 1 ? 1 : nums[right + 1]);
                    dp[left][right] = Math.max(dp[left][right], leftMax + rightMax + last);
                }
            }
        }
        return dp[0][nums.length - 1];
    }
}