目录
题目:
这是力扣的一条题目:
给定一个表示分数的非负整数数组。玩家1从数组任意一端拿取一个分数,随后玩家2继续从剩余数组任意一端拿取分数,然后玩家1拿....每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。
给定一个表示分数的数组,预测玩家1是否会成为嬴家。你可以假设每个玩家的玩法都会使他的分数最大化。
不太会的可以自己去看题解,里边讲的很详细。
我这里主要写下我自己从递归一直优化到动态规划(空间优化)的历程。(代码可以通过力扣的oj)
递归:
class Solution {
public:
int dfs(vector<int>&nums,int left,int right)
{//这里dfs的意义是当前操作的玩家分数与另一个玩家的分数之差
if(left == right)
return nums[left];
return max(nums[left] - dfs(nums,left+1,right),nums[right]-dfs(nums,left,right-1));
}//由于"玩家的玩法都会使他的分数最大化,所以当前玩家尽量选择自己比对方分数高的策略
bool PredictTheWinner(vector<int>& nums) {
return dfs(nums,0,nums.size()-1) >=0;//自己的分数与对方的分数之差不小于0.则自己的分数不小于对方的分数
}
};
时间效率很低,于是进行升级:
记忆化递归:
class Solution {
public:
int memory[20][20];//既然数据范围已经给定了那么直接定义数组大小
int dfs(vector<int>&nums,int left,int right)
{//这里dfs的意义是当前操作的玩家分数与另一个玩家的分数之差
if(memory[left][right]!=-1)
return memory[left][right];
if(left == right)
{
memory[left][right]=nums[left];
return nums[left];
}
int ans = max(nums[left] - dfs(nums,left+1,right),nums[right]-dfs(nums,left,right-1));
memory[left][right] = ans;
return ans;
}//由于"玩家的玩法都会使他的分数最大化,所以当前玩家尽量选择自己比对方分数高的策略
bool PredictTheWinner(vector<int>& nums) {
memset(memory,-1,sizeof(memory));
return dfs(nums,0,nums.size()-1) >=0;//自己的分数与对方的分数之差不小于0.则自己的分数不小于对方的分数
}
};
效率大大提高
然后通过总结递归的递推公式,不难联想到用动态规划代替递归:
动态规划:
class Solution {
public:
int dp[20][20];
bool PredictTheWinner(vector<int>& nums) {
for(int i = 0;i<nums.size();++i)
{
dp[i][i] = nums[i];//初始化
}
for(int step = 1;step<nums.size();++step)
{
for(int i = 0;i+step<nums.size();++i)
{
int j = i + step;
dp[i][j]=max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1]); //建议结合表格理解
}
}
return dp[0][nums.size()-1] >=0;
}
};
虽然原理相同,但是递归便于理解,动态规划代码优雅。
其实动态规划的代码还可以更加优雅!通过优化,dp数组可以减少至一维,进一步减少内存需求。
动态规划(空间优化版):
class Solution {
public:
int dp[20];
bool PredictTheWinner(vector<int>& nums) {
for(int i = 0;i<nums.size();++i)
{
dp[i]= nums[i];//初始化
}
for(int step = 1;step<nums.size();++step)
{
for(int i = 0;i+step<nums.size();++i)
{
int j = i + step;
dp[i]=max(nums[j]-dp[i],nums[i]-dp[i+1]); //建议结合表格理解
}
}
return dp[0] >=0;
}
};
这下代码就非常之nice
执行结果:
总结:
在一般思路的基础上不断精进。