题目描述:
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/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。
顶你一个~~~~
backtracking + memo-ization毫无悬念地超时了。。。
nums[l] * nums[m] * nums[r] + dp[l][m] + dp[m][r]略微难理解。。
博主的文章一直写得不错,谢谢
以最后被爆破的气球m为界限,把数组分为左右两个子区域
这句话是关键,我开始一直在想m到底是啥来着,想了好久也没猜出来。。
感谢补充!:D