一、题目
给定一个数组arr,代表数值不同的纸牌排成一条线,
玩家A和玩家B依次拿走每张纸牌
规定玩家A先拿 玩家B后拿
但是每个玩家每次只能拿走最左或最右的纸牌
玩家A和玩家B都很聪明
请返回最后获胜者的分数
二、题解
2.1 方法一:递归
思路:定义两个递归函数:先手函数和后手函数
先手函数:
终止条件:只剩下一张纸牌时,返回这张纸牌的数值大小
当剩下的不止一张纸牌的情况时:因为作为先手,既可以摸走最左侧的牌,也可以摸走最右侧的牌,如果先以先手摸走左侧的牌,得到的最终数值,就是最左侧的牌值+以后手摸剩下的牌所获得的值
如果先以先手摸走右侧的牌,得到的最终数值,就是最右侧的牌值+以后手摸剩下的牌所获得的值,题目有说摸牌的人都很聪明,所以他一定可以计算出这两种情况的较大值
后手函数:
终止条件:只剩一张牌时,此时作为后手是摸不到牌的,返回0
当剩下的不止一张纸牌的情况时:作为后手,摸牌是受先手影响的,如果先手摸走了左侧的牌,后手只能从剩下的牌中以先手的形式做选择,如果先手摸走了右侧的牌,后手只能从剩下的牌中以先手的形式做选择。但是先手一定会计算好,让后手得到的牌值,一定是这两种情况中较小的那种。
源码:
🐻
public static int g1(int[] arr,int L,int R){
if(L==R) {
return 0;
}
int p1=f1(arr,L+1,R);
int p2=f1(arr,L,R-1);
return Math.min(p1,p2);
}
public static int f1(int[] arr,int L,int R){
if(L==R) {
return arr[L];
}
int p1=arr[L]+g1(arr,L+1,R);
int p2=arr[R]+g1(arr,L,R-1);
return Math.max(p1,p2);
}
public static int win1(int[] arr){
int first=f1(arr,0,arr.length-1);
int second=g1(arr,0,arr.length-1);
return Math.max(first,second);
}
2.2 方法二:使用缓存
分析依赖关系
分析图:
🐯
源码:
public static int f2(int[] arr,int L,int R,int[][] fmap,int[][] gmap){
if(fmap[L][R]!=-1){
return fmap[L][R];
}
int ans=0;
if(L==R) {
ans= arr[L];
}else {
int p1=arr[L]+g2(arr,L+1,R,fmap,gmap);
int p2=arr[R]+g2(arr,L,R-1,fmap,gmap);
ans= Math.max(p1,p2);
}
fmap[L][R]=ans;
return ans;
}
public static int g2(int[] arr,int L,int R,int[][] fmap,int[][] gmap){
if(gmap[L][R]!=-1){
return gmap[L][R];
}
int ans=0;
if(L==R) {
ans= 0;
} else {
int p1=f1(arr,L+1,R);
int p2=f1(arr,L,R-1);
ans= Math.min(p1,p2);
}
gmap[L][R]=ans;
return ans;
}
public static int win2(int[] arr){
int N= arr.length;
int[][] fmap=new int[N][N];
int[][] gmap=new int[N][N];
for (int i = 0; i <N ; i++) {
for (int j = 0; j <N ; j++) {
fmap[i][j]=-1;
gmap[i][j]=-1;
}
}
int first=f1(arr,0,arr.length-1);
int second=g1(arr,0,arr.length-1);
return Math.max(first,second);
}
2.3 严格表依赖
分析图:
源码:
🐑
public static int win3(int[] arr){
int N= arr.length;
int[][] fmap=new int[N][N];
int[][] gmap=new int[N][N];
for (int i = 0; i < N; i++) {
fmap[i][i]=arr[i];
}
for (int startCol = 1; startCol <N ; startCol++) {
int L=0;
int R=startCol;
while(R<N){
fmap[L][R]=Math.max(arr[L]+gmap[L+1][R],arr[R]+gmap[L][R-1]);
gmap[L][R]=Math.min(fmap[L+1][R],fmap[L][R-1]);
L++;
R++;
}
}
return Math.max(fmap[0][N-1],gmap[0][N-1]);
}