解法1:
主要思路就是将戳气球的问题转化为往区间里加气球的问题,也就是将整个过程逆过来。solve(i, j)代表着(i, j)区间内所有气球全部被加好后,最多的coin个数。遍历(i,j)区间内第一个可以加的气球的位置mid,由于其他气球都还没加,所以此时加mid后coin个数为nums[mid]*nums[i]*nums[j],之后再以mid切割(i, j),分别计算solve(i, mid)和solve(mid, j)的值,便知道第一个加此mid位置时,最多能获得的coin数。遍历mid位置,取max,便可知道整体的能获取的最多coin个数。
就相当于遍历mid之后,将问题分为了两个子问题,将问题分治了。
虽然和官方题解中思路一样,但是python过不了,而且官方题解的这个思路的python代码也过不了,但是c++就能过,猜测是因为c++本身耗时相对比python短。
python代码:
class Solution:
def maxCoins(self, nums: List[int]) -> int:
result = 0
nums = [1] + nums + [1]
l = len(nums)
if l == 3:
return nums[1]
d = [[0 for i in range(l)] for j in range(l)]
def solve(i, j):
# 这里的判断是j-1
if i >= j-1:
return 0
if d[i][j] != 0:
return d[i][j]
tmpResult = 0
for mid in range(i+1, j):
tmpResult = max(tmpResult, nums[mid]*nums[i]*nums[j]+solve(i, mid)+solve(mid, j))
d[i][j] = tmpResult
return tmpResult
return solve(0, l-1)
C++代码(可过):
const int maxl = 500;
int so[maxl+2][maxl+2]; // 结果
int nums_1[maxl+2];
class Solution {
public:
int solve(int i, int j) {
if(i >= j-1) {
return 0;
}
if(so[i][j] != -1) {
return so[i][j];
}
int tmpResult = 0;
for(int mid = i+1; mid < j; mid++) {
int tmp = nums_1[mid]*nums_1[i]*nums_1[j]+solve(i, mid)+solve(mid, j);
if(tmp > tmpResult) {
tmpResult = tmp;
}
}
so[i][j] = tmpResult;
return tmpResult;
}
int maxCoins(vector<int>& nums) {
int l = nums.size();
memset(so, -1, sizeof(so));
// nums前后均加1
nums_1[0] = 1;
for(int i = 0; i < l; i++) {
nums_1[i+1] = nums[i];
}
// 由于开头加了1,所以此处索引要为l+1
nums_1[l+1] = 1;
return solve(0, l+1);
}
};