2020年9月1日 预测赢家 PredictTheWinner
class Solution {
public boolean PredictTheWinner(int[] nums) {
}
}
解题思路:
一般来说,这种游戏规则类题目考验的是你的逻辑能力,看你能否察觉到游戏的本质是什么,其实有很多的这种小游戏能够看穿本质之后就会变得很无聊。
思路1,使用递归。
我们的问题是,玩家1能否获胜。
那么我们可以试着改变思路,把问题变成,当玩家1选择的第1个或者玩家1选择了最后一个之后,玩家2是否能够得到的最大分数是否会比当时玩家1拿到的最大分数多出玩家1已经拿到的分数。
下面这个算法没有用到任何一点技巧,知识单纯的递归了所有可能性,我觉得时间大概率是超限了的。
int[] nums;
public boolean PredictTheWinner(int[] nums) {
this.nums=nums;
if (canWin(0,nums.length-1 )>=0){
return true;
}else
return false;
}
//返回先拿的比后拿的最多多多少分
public int canWin(int start,int end){
if (end<start){
return 0;
}
return Integer.max(nums[start]-canWin(start+1,end),nums[end]-canWin(start,end-1));
}
但是不可能这样就满意了的,肯定是要优化的,那么怎么优化呢?
优化1:
优化的最基础的一个方式,用空间换时间,我这里用一个len*len大小的二维数组记录递归过程中计算的结果,因为计算过程有一些是重复的,比如
1,2,3,4,5
第一次递归,玩家1拿1,玩家2拿5。剩下的3个继续递归。
第二次递归,玩家1拿5,玩家2拿1,剩下三个相同的但是任然需要递归。
我们的目的就是,剩下的三个我们记录下来,这样第二次递归之前发现已经计算过就不用递归了。这也算是一种递归的剪枝算法吧。
完美
int[] nums;
Integer[][] map;
public boolean PredictTheWinner(int[] nums) {
this.nums=nums;
map=new Integer[nums.length][nums.length];
if (canWin(0,nums.length-1 )>=0){
return true;
}else
return false;
}
//返回先拿的比后拿的最多多多少分
public int canWin(int start,int end){
if (end<start){
return 0;
}
if (map[start][end]==null){
int num1=nums[start]-canWin(start+1,end);
int num2=nums[end]-canWin(start,end-1);
map[start][end]=Integer.max(num1,num2);
return map[start][end];
}
else return map[start][end];
}