Burst Balloons动态规划求解

Leetcode第312题,Burst Balloons,这道题还是比较有难度。做出了后写一篇博客记录下。先上题目
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:

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 = 315 + 358 + 138 + 181 = 167
记录下我的解题思路:
输入是一个数组,每爆炸一个气球,就有一个数字消失,结果加上nums[left] * nums[i] * nums[right]。而显然每次爆炸left和right是哪个气球都不确定。那怎么做呢?

法一、回溯法暴力求解。
用回溯法找出所有解,取结果最大的一个。那么问题的解空间应该是数组中n个数字的全排列。排列不同,则它们的Left和right就不同。n<=500,故解空间最多有500!个解,显然时间、复杂度太高。

结果的上界:500个数字,每个数字消失时加上<=100 ^ 3 即10^6,则结果<= 500 * 10 ^ 6 = 5 * 10 ^ 8

法二、动态规划
这道题看上去可以用动态规划求解。显然可以用二维数组re来存放答案。但是如何确定动态规划的数学表达式呢?
设re[i][i + k]是消除第i到第i + k个数字得到的硬币。那么其中的数学关系是: re[i][i + k] = max(re[i][j - 1] + re[j + 1][i + k] + re[i - 1] * re[j] * re[i + k])。那么问题来了,为什么re[j]要乘re[i - 1]和re[i + k + 1]呢?如何保证消掉第j和数字的时候它的邻居是i - 1和i + k + 1而不是其它的呢?其实只要设计算re[i][i + k]即消掉第i到第i + k个数字时其它数字没被消掉就可以了。为什么可以这么设呢?因为是通过逐渐增大i + k的k 来计算的,这和实际情况是符合的。实际上消掉气球的顺序总是可以调整下变成消掉第 i 到第 i + k 个气球(k逐渐增大)的过程而不改变最终结果。
附下代码:

public int maxCoins(int[] nums) {
        int n = nums.length;
        int[] fixedNums = new int[n + 2];
        fixedNums[0] = fixedNums[n + 1] = 1;
        System.arraycopy(nums, 0, fixedNums, 1, n);
        int[][] re = new int[n + 2][n + 2];
        re[0][0] = re[n + 1][n + 1] = 1;
        for (int i = 1; i <= n; i++) {
            re[i][i] = fixedNums[i - 1] * fixedNums[i] * fixedNums[i + 1];
        }
        for (int k = 1; k < n; k++) {
            for (int i = 1; i + k <= n; i++) {
                int re1 = fixedNums[i] * fixedNums[i - 1] * fixedNums[i + k + 1]
                        + re[i + 1][i + k];
                int re2 = fixedNums[i + k] * fixedNums[i - 1] * fixedNums[i + k + 1]
                        + re[i][i + k - 1];
                int ren = Math.max(re1, re2);
                for (int j = i + 1; j < i + k; j++) {
                    int temp = fixedNums[j] * fixedNums[i - 1] * fixedNums[i + k + 1]
                            + re[i][j - 1] + re[j + 1][i + k];
                    ren = Math.max(temp, ren);
                }
                re[i][i + k] = ren;
            }
        }
        return re[1][n];
    }
```java

你可能感兴趣的:(动态规划)