leetcode312 - Burst Balloons -hard

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 rightare adjacent indices of i. After the burst, the left and right then becomes adjacent.
Find the maximum coins you can collect by bursting the balloons wisely.
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:
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

DP。O(n^3)
考虑消去型的dp,不好正面想消去后接下来怎么处理,要反过来想。先想最后一个消去的对象能得多少分,想最后一个对象消哪一个能让答案为最大值。
本题有一个特点:左右区间独立。消去最后一个气球时,气球左边的区间消去最优得分和气球右边的区间完全没关系。这是因为两边的气球被中间这个气球隔开了,左边区间最后一个气球分数才用到中间这个气球,再左边的气球更用不到中间及以后的气球了。利用这个特性,如果我们在[i,j]这段区间中间的k位置扎破最后一个气球,那么得分关系就有point[i,j] = point[i,k] + point[k,j] + 扎k得分。

dp[i][j]定义:区间[i, j]中扎气球能得的最大分数,保证i, j不被扎破。
初始化:所有长度为2的区间如dp[i, i+1]都初始化为0,因为两个边缘气球不能被扎破。
递推公式:dp[i][j] = Max(dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]), 对所有满足i < k < j 的k遍历。


细节:
1.区间型动态规划的推导顺序,最外层按区间长度循环渐增。然后内部先根据起始点i循环,由i和len可以直接得到j。i的循环条件根据j的下标要在什么范围内可以推得。
2.最开始先对nums扩充一下左右两边比较好,也就是最左边和最右边有一个nums[i] == 1的不能扎破的气球,这样好算原始数据里最边缘两个气球被扎破时的得分。

实现:

class Solution {
    public int maxCoins(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int[][] dp = new int[nums.length + 2][nums.length + 2];
        int[] temp = new int[nums.length + 2];
        temp[0] = temp[temp.length - 1] = 1;
        for (int i = 0; i < nums.length; i++) {
            temp[i + 1] = nums[i];
        }
        nums = temp;
        
        dp[0][0] = 0;
        for (int i = 1; i < dp.length; i++) {
            dp[i][i] = 0;
            dp[i - 1][i] = 0;
        }
        
        
        for (int dist = 2; dist <= dp.length - 1; dist++) {
            for (int i = 0; i + dist < dp[0].length; i++) {    
                int j = i + dist;
                dp[i][j] = 0;
                for (int k = i + 1; k < j; k++) {
                    dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k][j] + nums[i] * nums[k] * nums[j]);
                }
            }
        }
        return dp[0][dp[0].length - 1];
        
    }
}

猜你喜欢

转载自www.cnblogs.com/jasminemzy/p/9660227.html