题目
给定一个数组,每个元素代表卡牌分数,规定每次A先拿,然后B拿,每次拿牌只能拿最左或最右的一张牌,玩家A、B都绝顶聪明,返回最后获胜者的分数(最大分数); 举例:[1,2,100,4],开始时A只能拿1或4,玩家A作为绝顶聪明的人绝不会拿4,因为拿4后B可以拿到100,所以玩家A会先拿1,然后B拿4,然后A拿100,然后B拿2结束游戏
- 因为并不能预先知道A拿哪边是最优解,所以需要构造拿左边和拿右边的两条路,最终通过Math.max来获得A最大分数
- 当A拿了一次后,因为B绝顶聪明,所以留给A的一定是最小的,所以第二次选择时,需要根据可选区间,选择最小的那条路,并且当第二次选择只有一个数时,需要B选,A不能再选了,返回0,当选择时只剩一个数,直接返回该数
function winner(arr) {
// 在选择时,选择可选区间最大的那个
function choose(arr, i, j) {
// 因为是先选,当区间只剩一个数时,就只能选择该数
if (i === j) {
return arr[i];
}
// 因为先手选了,所以在剩余区间要别人先选再后手选,所以secondChoose表示在剩余区间后手选的分数
return Math.max(
arr[i] + secondChoose(arr, i + 1, j),
arr[j] + secondChoose(arr, i, j - 1)
);
}
// secondChoose实际上还是递归调用choose进行选择
function secondChoose(arr, i, j) {
// 因为是后手选,当区间只剩一个数时,返回0
if (i === j) {
return 0;
}
// 因为是后手选,所以留下的一定是最小的那个,只能选最小的那个
// i+1表示先手选了i位置,j-1表示先手选了j位置
return Math.min(choose(arr, i + 1, j), choose(arr, i, j - 1));
}
return Math.max(
choose(arr, 0, arr.length - 1), //先选玩家
secondChoose(arr, 0, arr.length - 1)//后选玩家
);
// return choose(arr,0,arr.length-1)
// return secondChoose(arr,0,arr.length-1)
}
//[1,2,100,4]
//[1,100,2]
console.log(winner([1, 100, 2]));