一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【LeetCode 486. 预测赢家 】- JavaScript(递归+DP)
给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。
玩家 1 和玩家 2 轮流进行自己的回合,玩家 1 先手。开始时,两个玩家的初始分值都是 0 。每一回合,玩家从数组的任意一端取一个数字(即,
nums[0] 或 nums[nums.length - 1]),取到的数字将会从数组中移除(数组长度减 1 )。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时,游戏结束。如果玩家 1 能成为赢家,返回 true 。如果两个玩家得分相等,同样认为玩家 1 是游戏的赢家,也返回 true 。你可以假设每个玩家的玩法都会使他的分数最大化。
示例 1:
输入:nums = [1,5,2]
输出:false
解释:一开始,玩家 1 可以从 1 和 2 中进行选择。
如果他选择 2(或者 1 ),那么玩家 2 可以从 1(或者 2 )和 5 中进行选择。
如果玩家 2 选择了 5 ,那么玩家 1 则只剩下 1(或者 2 )可选。
所以,玩家 1 的最终分数为 1 + 2 = 3,而玩家 2 为 5 。 因此,玩家 1 永远不会成为赢家,返回 false 。
思路分析
这道题目有下面是个核心问题,解了它们这题就不在话下了。
- 怎么求出其中一个数组的最优解
- 怎么进行合并已经求出的两个数组的结果
- 如何进行数组的比较
可以说让人崩溃,做完这道题,相当于写了三道题。如果面试遇到这种题目,你应该懂面试官什么意思了,他对你不满意。
递归
题意描述
思路:diff返回(玩家1-玩家2)的分数差,玩家1希望该差越大越好,玩家2希望该差越小越好。
具体步骤:
- 首先,对原问题进行一个小的转换,玩家1分数 不小于 玩家2,则获胜。 可以转换成 玩家1分数 - 玩家2分数 >= 0 ,则玩家获胜。
- 分别遍历 玩家1 每次取首端,尾端的值,取最大值。
- 分别遍历 玩家2 每次取首端、尾端的值,取数值最大的数,由于进行了转换,总分数 -= 玩家2 的分数,所以应该取总分数的最小值。
var PredictTheWinner = function(nums) {
return dfs(0, nums.length - 1, 0, 0, true);
function dfs(start, end, score1, score2, canChoose) {
if (start > end) {
return score1 >= score2;
}
if (canChoose) {
canChoose = !canChoose;
if (dfs(start + 1, end, score1 + nums[start], score2, canChoose) || dfs(start, end - 1, score1 + nums[end], score2, canChoose)) {
return true;
}
} else {
canChoose = !canChoose;
if (dfs(start + 1, end, score1, score2 + nums[start], canChoose) && dfs(start, end - 1, score1, score2 + nums[end], canChoose)) {
return true;
}
}
return false;
}
};
动态规划
分析
如果假设玩家1在数组的任意一段位置
[i, j]; 0 <= i <= j <= len-1;
- 那么此时玩家1可以选择i或选择j;
- 那么玩家2可以从剩余[i+1,j] 或[i, j-1]中选择最大值
使用 DP来记录用户选择的答案。那么可以推导出如下公式
dp[i][j] = Math.max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])如果我们是
使用dp[i,j]来存储可以选择的最大值和。那么转移方程应该为subSum = sum(i+1, j) max(nums[i] + (subSum - dp[i+1][j]), nums[j] + (subSum - dp[i][j-1])) return dp[0][len-1] * 2 >= sum;这样每次都需要计算子数组的和,麻烦有耗时就没有必要。
var PredictTheWinner = function(nums) {
const n = nums.length
const dp = new Array(n)
for (let i = 0; i < n; i ++) {
dp[i] = new Array(n)
dp[i][i] = nums[i]
}
for (let i = n-2; i >= 0; i --) {
for (let j = i+1; j < n; j ++) {
const head = nums[i]-dp[i+1][j]
const tail = nums[j]-dp[i][j-1]
dp[i][j] = Math.max(head, tail)
}
}
return dp[0][n-1] >= 0
};
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤