[Leetcode] 312. Burst Balloons 解题报告

来源:互联网 发布:为什么服务器用centos 编辑:程序博客网 时间:2024/05/16 12:06

题目

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

思路

1、动态规划:动态规划是这道题目最容易想到的解。为了便于处理边界情况,我们给nums的首位分别加入1,然后定义dp[i][j]表示在区间[i,j]内的最优解。显然可以得到如下状态转移方程:dp[i][j] = max(dp[i][k - 1] + dp[k + 1][j] + nums[i - 1] * nums[k] * nums[j + 1] ),其中i <= k <= j。max函数里面的表达式表示最后爆破第k个气球所产生的收益。该算法的时间复杂度是O(n^3),空间复杂度是O(n^2)。由于dp[i][j]和区间内的所有子状态都有关,所以空间复杂度无法再次进行优化。

2、分治:我觉得虽然叫做分治,其实也算是一道DFS+记忆。也就是我们在递归求解的过程中,如果发现子问题已经被解决了,就直接利用;否则就先解决子问题。而判断子问题是否被解决的方法就是看dp[low][high]是否大于0,如果大于0,就说明已经被计算出来了,就直接利用。所以分支从时间和空间复杂度上和动态规划都一样,甚至本质都是一样的。但是由于分治涉及到了递归调用,所以在实际运行中会花费更多的时间。

代码

1、动态规划:

class Solution {public:    int maxCoins(vector<int>& nums) {        if (nums.size() == 0) {            return 0;        }        int n = nums.size(), temp = 0;        nums.insert(nums.begin(), 1), nums.push_back(1);        vector<vector<int>> dp(nums.size() + 1, vector<int>(nums.size() + 1, 0));        for(int len = 1; len <= n; ++len) {            for(int left = 1; left + len <= n + 1; ++left) {                int right = left + len - 1;                for(int k = left; k <= right; ++k) {                    temp = nums[left - 1] * nums[k] * nums[right + 1] + dp[left][k - 1] + dp[k + 1][right];                    dp[left][right] = max(temp, dp[left][right]);                }            }        }        return dp[1][n];    }};

2、分治:

class Solution {public:    int maxCoins(vector<int>& nums) {        if (nums.size() == 0) {            return 0;        }        nums.insert(nums.begin(), 1), nums.push_back(1);        vector<vector<int>> dp(nums.size() + 1, vector<int>(nums.size() + 1, 0));        return divide(nums, dp, 1, nums.size() - 2);    }private:    int divide(vector<int>& nums, vector<vector<int>>& dp, int low, int high) {        if(low > high) {            return 0;        }        if(dp[low][high] > 0) {         // keypoint: the value has already been calculated            return dp[low][high];        }        int ret = 0;        for(int i = low; i <= high; ++i) {            int temp = nums[low - 1]*nums[i]*nums[high + 1] + divide(nums, dp, low, i - 1) + divide(nums, dp, i + 1, high);            ret = max(ret, temp);        }        dp[low][high] = ret;        return ret;    }};