LeetCode算法网站算法题
https://leetcode-cn.com/problems/burst-balloons/
其实思路是一样的,就是动态规划,dp[i][j](或者rec[i][j])表示的是,第i个气球为删除气球的左气球,第j个气球为删除气球的右气球,记住有一点是删除最后一个气球时左气球是1,右气球也是1,这两个气球是不存在的,但是为了方便我们重新用一个数组来储存气球数据,最左边和最右边的是模拟实际情况的两个值,而且数组的下标也更好操作。
1.记忆化搜索
class Solution
{
private:
vector<int>data;
vector<vector<int>>rec;
int add(int left,int right)//这个函数的意义是计算最后一次戳爆的气球左边的气球是left右边的气球是right的情况下的最大价值
{
if(left>=right-1)//如果这里是left>=right的话,那么rec[right-1][right]这种表示两个相邻的点位不能被正确赋值为0,还是-1导致错误
return 0;
if(rec[left][right]!=-1)//记忆化搜索,如果已经计算过了就直接返回
return rec[left][right];
for(int i=left+1;i<right;i++)//枚举left和right的中间值,也就是枚举最后戳爆的气球,取最大的价值
{
int sum=data[i]*data[left]*data[right];//求最后那次戳爆产生的价值
sum+=add(left,i)+add(i,right);//想求left和right中间最大值,枚举了中间值之后还要递归的求left到i的最大价值,i到right的最大价值,相加起来
rec[left][right]=max(sum,rec[left][right]);
}
return rec[left][right];
}
public:
int maxCoins(vector<int>& nums)
{
int n=nums.size();
data.resize(n+2,1);//这里全部初始化为1的目的是当戳爆第一个或者最后一个气球的时候可以正确的计算价值的两个假设气球
rec.resize(n+2,vector<int>(n+2,-1));//初始化为-1的目的是标记
for(int i=1;i<=n;i++)
{
data[i]=nums[i-1];//为了方便下标一致,方便操作
}
return add(0,n+1);
}
};
2.动态规划——如果说记忆化搜索是直观的自定向下的实现,那么动态规划就是自底向上实现,需要注意的是由于 dp[i][j]=max(dp[i][k]+dp[k][j]+data[i]*data[j]*data[k])(k从i+1到j-1循环)这个状态转移方程,所以我们的动态规划数组的行需要从底下向上的更新,而列需要从左边向右边的更新,最终返回dp[0][n+1]。至于思路和上面是一样的,不过多赘述了!
class Solution
{
public:
int maxCoins(vector<int>& nums)
{
int n=nums.size();
vector<int>data(n+2,1);
for(int i=1;i<n+1;i++)
{
data[i]=nums[i-1];
}
vector<vector<int>>dp(n+2,vector<int>(n+2,0));
for(int i=n-1;i>=0;i--)
{
for(int j=i+2;j<n+2;j++)
{
for(int k=i+1;k<j;k++)
{
int sum=data[i]*data[j]*data[k];
sum+=dp[i][k]+dp[k][j];
dp[i][j]=max(dp[i][j],sum);
}
}
}
return dp[0][n+1];
}
};