原题链接:https://leetcode-cn.com/problems/predict-the-winner/
1、递归
每次从头和尾各选一个,然后接着取下一个状态的小的那一个,因为对方肯定把大的取走了,然后最后的结果取最大,所以这题也是最大的最小,max(min()),不同于猜数字大小 II,这题是最好的最坏,是min(max())
bool PredictTheWinner(vector<int>& nums) {
int len=nums.size();
int sum=0;
for(auto x:nums) sum+=x;
if(2*select(nums,0,len-1)>=sum) return true;
else return false;
}
int select(vector<int>& nums,int start,int end){
if(start>end) return 0;
if(start==end) return nums[start];
int x=nums[start]+min(select(nums,start+2,end),select(nums,start+1,end-1));
int y=nums[end]+min(select(nums,start+1,end-1),select(nums,start,end-2));
return max(x,y);
}
2、动态规划(自底向上)
动态规划的方法是比较巧妙
dp[i][j]保存从i到j领先一方领先的数
状态转移
dp[i][i]=nums[i]
dp[i][j]=max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1])
dp[i][i]代表只有这一个数,那么先手者肯定就直接拿走了。
这里dp[i+1][j]和dp[i][j-1]都是表示上次另外一方的领先数,使用nums[i]-dp[i+1][j]或nums[j]-dp[i][j-1]就表示分别选头部和尾部之后,领先的数。于是,若dp[0][len-1]>0表示先手领先,先手赢。若dp[0][len-1]=0表示平局,按题意,也是先手赢。
bool PredictTheWinner(vector<int>& nums) {
int len=nums.size();
vector<vector<int>> dp(len,vector<int>(len,0));
for(int i=0;i<len;i++) dp[i][i]=nums[i];
for(int i=len-1;i>=0;i--){
for(int j=i+1;j<len;j++){
dp[i][j]=max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1]);
}
}
return dp[0][len-1]>=0;
}
3、动态规划(自顶向下)
bool PredictTheWinner(vector<int>& nums) {
int len=nums.size();
vector<vector<int>> dp(len,vector<int>(len,0));
for(int i=0;i<len;i++) dp[i][i]=nums[i];
for(int size=1;size<len;size++){
for(int i=0;i<len-size;i++){
int j=i+size;
dp[i][j]=max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1]);
}
}
return dp[0][len-1]>=0;
}
这种方法是不是和猜数字大小非常相似呢?