395. 硬币排成线 II
中文English
有 n
个不同价值的硬币排成一条线。两个参赛者轮流从 左边 依次拿走 1 或 2 个硬币,直到没有硬币为止。计算两个人分别拿到的硬币总价值,价值高的人获胜。
请判定 先手玩家 必胜还是必败?
若必胜, 返回 true
, 否则返回 false
.
样例
样例 1:
输入: [1, 2, 2]
输出: true
解释: 先手玩家直接拿走两颗硬币即可.
样例 2:
输入: [1, 2, 4]
输出: false
解释: 无论先手拿一个还是两个, 后手可以拿完, 然后总价值更高.
输入测试数据 (每行一个参数)如何理解测试数据?
解法一:动态规划
dp[i]代表的是倒数n-i个,逆着算,例如dp[length - 2] = values[length - 2] + values[length - 1] ,表示的是i到length - 1可以拿到的最大值
class Solution: """ @param values: a vector of integers @return: a boolean which equals to true if the first player will win """ def firstWillWin(self, values): # write your code here #动态规划 #如果是len(values)<= 3的情况,则直接给出答案 #如果是len(valeus) > 3的情况,分情况,要么先手拿一个,要么拿两个 length = len(values) if (length <= 2): return True dp = [0 for _ in range(length + 1)] total = 0 #如果是<=3的话 #如果是只拿最后一个的话,先手必拿 dp[length - 1] = values[length - 1] #如果是剩余最后两个的话,先手也必拿 dp[length - 2] = values[length - 1] + values[length - 2] #如果是剩余三个的话,那么先手最优策略是拿前两个,最后一个留给后手 dp[length - 3] = values[length - 2] + values[length - 3] total = sum(values[length - 3:]) #如果是大于3的话,分情况考虑 for i in range(length - 4, -1, -1): total += values[i] #先手要么拿一个,要么拿两个,后手也是最优策略,所以后手也尽可能的多拿,min(dp[i + 2], dp[i + 3]) dp[i] = max(values[i] + min(dp[i + 2], dp[i + 3]), values[i] + values[i + 1] + min(dp[i + 3], dp[i + 4])) #最后比较两者大小,肯定是先手拿,也就是第一个 return dp[0] > total - dp[0]
394. 硬币排成线
中文English
有 n
个硬币排成一条线。两个参赛者轮流从右边依次拿走 1 或 2 个硬币,直到没有硬币为止。拿到最后一枚硬币的人获胜。
请判定 先手玩家 必胜还是必败?
若必胜, 返回 true
, 否则返回 false
.
样例
样例 1:
输入: 1
输出: true
样例 2:
输入: 4
输出: true
解释:
先手玩家第一轮拿走一个硬币, 此时还剩三个.
这时无论后手玩家拿一个还是两个, 下一次先手玩家都可以把剩下的硬币拿完.
挑战
O(1) 时间复杂度且O(1) 存储。
输入测试数据 (每行一个参数)如何理解测试数据?
解法:动态规划
class Solution: """ @param n: An integer @return: A boolean which equals to true if the first player will win """ def firstWillWin(self, n): # write your code here #当前必胜和必败由前面两个决定 #只考虑先手,and表示的是后手的最优策略,只要有前面先手有一个为False,那么后手一定是True #dp[i] = dp[i - 2] and dp[i - 3] or dp[i - 3] and dp[i - 4] #当前先手 = 取一个后手的最优策略 取两个后手的最优策略(所以中间是and,表示,只要之前先手一个为False,此时后手采取最优策略,一定为True) if not n: return False if n <= 2: return True dp = [False for _ in range(n + 1)] #前面三个的话,是固定 dp[1] = True dp[2] = True dp[3] = False for i in range(4, n + 1): dp[i] = (dp[i - 2] and dp[i - 3]) or (dp[i - 3] and dp[i - 4]) return dp[n]