题目描述:
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 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
题目大意:
给定n个气球,下标为0到n-1。每个气球上都标有一个数字,用数组nums表示。你被要求扎破所有气球。扎破第i个气球可以获得nums[left] * nums[i] * nums[right]枚硬币。这里left和right是与i相邻的下标。扎破气球以后,left和right就变成相邻的了。
寻找最优策略下可以获得的硬币数。
注意:
(1) 你可以假设nums[-1] = nums[n] = 1. 它们并非真实的因此不能扎破。
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
解题思路:
动态规划(Dynamic Programming)
时间复杂度O(n ^ 3)
参考peisi的答案:https://leetcode.com/discuss/72216/share-some-analysis-and-explanations
以最后被爆破的气球m为界限,把数组分为左右两个子区域
状态转移方程:
dp[l][r] = max(dp[l][r], nums[l] * nums[m] * nums[r] + dp[l][m] + dp[m][r])
dp[l][r]表示扎破(l, r)范围内所有气球获得的最大硬币数,不含边界;
l与r的跨度k从2开始逐渐增大;
三重循环依次枚举范围跨度k,左边界l,中点m;右边界r = l + k;
状态转移方程在形式上有点类似于Floyd最短路算法。
Java代码:
public class Solution {
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;
int[][] dp = new int[n][n];
for (int k = 2; k < n; ++k)
for (int l = 0; l < n - k; ++l) {
int r = l + k;
for (int m = l + 1; m < r; ++m)
dp[l][r] = Math.max(dp[l][r],
nums[l] * nums[m] * nums[r] + dp[l][m] + dp[m][r]);
}
return dp[0][n - 1];
}
}
本文链接:http://bookshadow.com/weblog/2015/11/30/leetcode-burst-balloons/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。
奶爸网 naiba.im 发布于 2015年12月2日 08:31 #
顶你一个~~~~
大王驮我去巡山 发布于 2016年1月1日 21:00 #
backtracking + memo-ization毫无悬念地超时了。。。
nums[l] * nums[m] * nums[r] + dp[l][m] + dp[m][r]略微难理解。。
博主的文章一直写得不错,谢谢
cpd0101 发布于 2016年3月6日 22:31 #
以最后被爆破的气球m为界限,把数组分为左右两个子区域
大睿-SCTrojan 发布于 2016年3月14日 03:56 #
这句话是关键,我开始一直在想m到底是啥来着,想了好久也没猜出来。。
在线疯狂 发布于 2016年3月14日 22:19 #
感谢补充!:D