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 = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
题目理解:
给定一个数组,每一次消除其中一个数字num,消除这个数字的得分,是num与其相邻两个数的乘积
解题思路:
动态规划算法。动态规划问题解的最终形态是自底向上解决问题,我做这个题目的时候只实现到了使用递归+记录的低级形式,但是好处是比较好理解。
如果将整个数组分成两个部分来分治,那么两个部分的解会有关联,因为某一部分边界值计算会用到另一部分的边界值。
因此考虑将数组分为三个部分,左边是一个子数组left,中间是一个数字num,右边是一个子数组right,计算num是最后消除的数的时候,最大的得分是多少。
借助分治,我们可以得到right部分的最优解和left部分的最优解,当left和right中所有的数字都已经消除完毕时,再消除num的得分就是num,因此合并的方式就是result[left]+num+result[right]
如果left中只剩下一个数n,那么得分就是n;如果left中一个数也没有,那么得分就是0
在得到了一个子数组的最优之后,我们将这个最优解记录下来,如果之后还遇到求这个子数组最优解的情况,我们就可以直接用了
class Solution {
int[] nums;
int len;
Map<String, Integer> map = new HashMap<>();
public int helper(int left, int right){
int leftBound = left - 1, rightBound = right + 1;
String str = left + " " + right;
if(map.containsKey(str))
return map.get(str);
if(left > right)
return 0;
int res = 0;
int leftValue = leftBound < 0 ? 1 : nums[leftBound];
int rightValue = rightBound >= len ? 1 : nums[rightBound];
for(int i = left; i <= right; i++){
int leftRes = helper(left, i - 1);
int rightRes = helper(i + 1, right);
res = Math.max(res, leftRes + rightRes + nums[i] * leftValue * rightValue);
}
//System.out.println(left + " " + right + " " + leftBound + " " + rightBound + " " + res);
map.put(str, res);
return res;
}
public int maxCoins(int[] nums) {
this.nums = nums;
len = nums.length;
return helper(0, len - 1);
}
}