LeetCode[312] Burst Ballons

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.

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

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

Example:

Given [3, 1, 5, 8]

Return 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

复杂度
O(N^2), O(N^2)

思路
DP的思想是bottom up, 每次的想法是设置一个window size = k, 并且这是left和right的window范围。在某一个window之下,考虑这个window内的能够组成的最大值,不断的扩大这个window size进行搜索。

代码
这是一个找到的写的比较清晰的代码,可以参考。

public int maxCoins(int[] iNums) {
    // 开头和结尾补充1,用来处理两侧的可能性。
    int[] nums = new int[iNums.length + 2];
    int n = 1;
    for (int x : iNums) if (x > 0) nums[n++] = x;
    nums[0] = nums[n++] = 1;
    
    // dp[i][j]表示从i到j这个window范围内,能组成的最大值
    int[][] dp = new int[n][n];
    // 设置window间隔
    for (int k = 2; k < n; ++k)
        for (int left = 0; left < n - k; ++left) {
            // window[left, right]
            int right = left + k;
            for (int i = left + 1; i < right; ++i)
                dp[left][right] = Math.max(dp[left][right], 
                nums[left] * nums[i] * nums[right] + dp[left][i] + dp[i][right]);
        }

    return dp[0][n - 1];
}

D&C + Memorization

复杂度
O(N^3) ?, O(N^2)

思路
memorization是from top to bottom,每一次都将值分成两部分,然后分别计算。对于在left和right中间的位置i,考虑[left,i]和[i,right]能组成的部分,分别对这两部分进行递归求值。用二维数组记录已经计算过的值,避免重复计算。

代码
同样是摘抄的别人的代码。

public int maxCoins(int[] iNums) {
    int[] nums = new int[iNums.length + 2];
    int n = 1;
    for (int x : iNums) if (x > 0) nums[n++] = x;
    nums[0] = nums[n++] = 1;
    // memo[i][j] 表示从i位到第j位能形成的max value
    int[][] memo = new int[n][n];
    return burst(memo, nums, 0, n - 1);
}

public int burst(int[][] memo, int[] nums, int left, int right) {
    // 说明[left,right]中间没有ballon可以炸掉
    if (left + 1 == right) return 0;
    // 加快搜索,避免重复计算
    if (memo[left][right] > 0) return memo[left][right];
    int ans = 0;
    for (int i = left + 1; i < right; ++i)
        ans = Math.max(ans, nums[left] * nums[i] * nums[right] 
        + burst(memo, nums, left, i) + burst(memo, nums, i, right));
    memo[left][right] = ans;
    return ans;
}

hellolittleJ17
10 声望11 粉丝