有 n 个气球,编号为0 到 n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。如果你戳破气球 i ,就可以获得 nums[left] * nums[i] * nums[right] 个硬币。这里的 left 和 right 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球。
求所能获得硬币的最大数量。
题解:
1.n 个气球
2.戳破气球 i ,就可以获得 nums[left] * nums[i] * nums[right] 个硬币,left 和 right 与 i 相邻
3.戳破 i 后,气球 left 和气球 right 相邻
4.这里戳破气球的选择顺序有很多,结果是能得到最大硬币数量的方式计算
说明:
你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。
0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
示例:
输入: [3,1,5,8]
输出: 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,重建一维容器把这两个元素加进去
-
考虑使用一个二维容器记录中间结果,减少递归过程中重复计算值
-
把新建的数组从头到尾不断一分为二的递归计算和值,有重复计算数值内容直接返回数组元素
-
题目要求最大数量,每次递归计算出和值都选取较大者,保证最后整个数组获得最大硬币数量
C/C++题解:
class Solution {
public:
vector<vector<int>> rec;
vector<int> val;
int solve(int left, int right) {
if (left >= right - 1) {//左右双指针
return 0;
}//如果已经计算过了值,直接从数组返回减少重复计算
if (rec[left][right] != -1) {
return rec[left][right];
}//从左边界到右边界,从第二个元素计算
for (int i = left + 1; i < right; i++) {
int sum = val[left] * val[i] * val[right];
sum += solve(left, i) + solve(i, right);//左右分别进一步计算
rec[left][right] = max(rec[left][right], sum); }//选出最大数量
return rec[left][right];}
int maxCoins(vector<int>& nums) {
int n = nums.size();
val.resize(2,1);//把数组index=-1,n的位置为1补齐
val.insert(val.begin() + 1, nums.begin(), nums.end());
//-1初始化记忆容器,注意加了头尾元素1
rec.resize(n + 2, vector<int>(n + 2, -1));
return solve(0, n + 1); }};
Debug结果:
Java题解:
class Solution {
public int[][] rec;
public int[] val;
public int solve(int left, int right) {
if (left >= right - 1) {//左右双指针 return 0;
}//如果已经计算过了值,直接从数组返回减少重复计算
if (rec[left][right] != -1) {
return rec[left][right];
}//从左边界到右边界,从第二个元素计算
for (int i = left + 1; i < right; i++) {
int sum = val[left] * val[i] * val[right];
sum += solve(left, i) + solve(i, right);//左右分别进一步计算
rec[left][right] = Math.max(rec[left][right], sum); }//选出最大数量
return rec[left][right]; }
public int maxCoins(int[] nums) {
int n = nums.length;
val = new int[n + 2];
for (int i = 1; i <= n; i++) {
val[i] = nums[i - 1]; }
val[0] = val[n + 1] = 1;//把数组index=-1,n的位置为1补齐
//-1初始化记忆容器,注意加了头尾元素1
rec = new int[n + 2][n + 2];
for (int i = 0; i <= n + 1; i++) {
Arrays.fill(rec[i], -1); }
return solve(0, n + 1); }}
Debug结果:
Python题解:
class Solution(object):
def maxCoins(self, nums):
""":type nums: List[int]:rtype: int"""
rec = [[-1 for _ in range(len(nums)+2)] for _ in range(len(nums)+2)]
val = [1] + nums + [1]
def solve(left, right):
if left >= right - 1: #左右双指针
return 0
#如果已经计算过了值,直接从数组返回减少重复计算
if rec[left][right] != -1:
return rec[left][right]
#从左边界到右边界,从第二个元素计算
for i in range(left+1, right):
count = val[left] * val[i] * val[right]
count += solve(left, i) + solve(i, right) #左右分别进一步计算
rec[left][right] = max(rec[left][right], count) #选出最大数量
return rec[left][right]
return solve(0, len(nums)+1)
Debug结果:
更多题解移步公众号免费获取