LeetCode 464 - Can I Win - Medium (Python)

In the "100 game," two players take turns adding, to a running total, any integer from 1..10. The player who first causes the running total to reach or exceed 100 wins.

What if we change the game so that players cannot re-use integers?

For example, two players might take turns drawing from a common pool of numbers of 1..15 without replacement until they reach a total >= 100.

Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally.

You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal will not be larger than 300.

Example

Input:
maxChoosableInteger = 10
desiredTotal = 11

Output:
false

需要注意的是这题的数字是不能重复使用的。以及超出desiredTotal也算赢。思路: dfs。      1) dfs跳出的条件是可以选的nums中最大的数字也比此时的target大。比如现在可以选的数字有[1,2,3,6,7,8]。target是7,那么我们可以直接出8就赢得比赛了。      2) dfs memorization 剪枝别忘了。

步骤: 1 构造nums,即所可以选的全部num的list。nums = [i for i in range(1, maxChoosableInteger+1)].       2 在进入dfs之前,可以预判˜˜。如果sum(nums) 大于desiredInteger,那么我们可以直接return False。 (因为所有的数字都只能用一次!!)如果sum(nums)刚好等于desiredInteger,并且len(nums) %2 != 0, 那么我们可以直接返回True。      3 构造一个self.seen = {}来记录所有出现过的nums的组合,以及其所对应的值(True or False)      4 进入dfs。 def can_win(self, nums, desiredTotal)      在dfs中,我们首先判断nums[-1],也就是此时最大的数字是否比我们desiredTotal大,大的话,return True. 第二步判断这个nums是否有出现在self.seen过。如果有的话,return self.seen[tuple(nums)].(需要注意的是,因为nums是一个list,我们需要转成tuple之后才可以转成tuple保存在self.seen中。) 如果上面两个判断都不符合的话,那就开始对nums遍历。假设我们选的是nums[i],意味着进入下一步dfs循环时候的nums是nums[:i] + nums[i+1:], desiredTotal变成了desiredTotal - nums[i]. 并且需要注意的是,这一步的循环是对于对手来说的,那么如果我们得到的下一步循环的结果是True,意味着这一步的结果是False(因为对手成功了,对我们来说就是失败)。如果有任何一种下一步的情况是False的话,意味着我们这时候的结果是True的。那我们把这个状态下的结果就可以保存在self.seen中,同时直接return True。如果所有的num都遍历过了,我们还是不能找到一个True的状态,那么也就把这个状态保存,值为False。同时return False。
class Solution:
    def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:
        if maxChoosableInteger >= desiredTotal:
            return True
        nums = [i for i in range(1, maxChoosableInteger+1)]
        if sum(nums) < desiredTotal:
            return False
        if sum(nums) == desiredTotal and len(nums) % 2 != 0:
            return True 

        self.seen = {}

        return self.can_win(nums, desiredTotal)

    def can_win(self, nums, target):
        if nums[-1] >= target:
            return True
        if tuple(nums) in self.seen:
            return self.seen[tuple(nums)]

        for i in range(len(nums)):
            if not self.can_win(nums[:i] + nums[i+1:], target-nums[i]):
                self.seen[tuple(nums)] = True
                return True
        self.seen[tuple(nums)] = False
        return False 


原文地址:https://www.cnblogs.com/sky37/p/12239515.html

时间: 2024-11-05 17:26:17

LeetCode 464 - Can I Win - Medium (Python)的相关文章

状态压缩 - LeetCode #464 Can I Win

动态规划是一种top-down求解模式,关键在于分解和求解子问题,然后根据子问题的解不断向上递推,得出最终解 因此dp涉及到保存每个计算过的子问题的解,这样当遇到同样的子问题时就不用继续向下求解而直接可以得到结果.状态压缩就是用来保存子问题的解的,主要思想是把所有可能的状态(子问题)用一个数据结构(通常是整数)统一表示,再用map把每个状态和对应结果关联起来,这样每次求解子问题时先find一下,如果map里面已经有该状态的解就不用再求了:同样每次求解完一个状态的解后也要将其放入map中保存 状态

[LeetCode]题解(python):029-Divide Two Integers

题目来源: https://leetcode.com/problems/divide-two-integers/ 题意分析: 不用乘法,除法和mod运算来实现一个除法.如果数值超过了int类型那么返回int的最大值. 题目思路: 初步来说,有两个做法. ①模拟除法的过程,从高位开始除,不够先右挪一位.这种方法首先要将每一位的数字都先拿出来,由于最大int类型,所以输入的长度不超过12位.接下来就是模拟除法的过程. ②利用左移操作来实现出发过程.将一个数左移等于将一个数×2,取一个tmp = di

[LeetCode]题解(python):131-Palindrome Partitioning

题目来源: https://leetcode.com/problems/palindrome-partitioning/ 题意分析: 给定一个字符串s,将s拆成若干个子字符串,使得所有的子字符串都是回文字符串,返回所有这样的子字符串集合.比如s = “aab”,那么返回[["aa","b"],["a","a","b"]]. 题目思路: 这是一个动态规划问题,如果s[:i]是回文字符串,那么s[:i] X s

[LeetCode]题解(python):115-Distinct Subsequences

题目来源: https://leetcode.com/problems/distinct-subsequences/ 题意分析: 给定字符串S和T,判断S中可以组成多少个T,T是S的子串. 题目思路: 这是一个动态规划的问题.设定ans[i][j]为s[:i] 组成t[:j]的个数.那么动态规划方程为,if s[i - 1] == t[j - 1]: ans[i][j] = ans[i - 1][j - 1] + ans[i - 1][j]:else: ans[i][j] = ans[i - 1

[LeetCode]题解(python):095-Unique Binary Search Trees II

题目来源: https://leetcode.com/problems/unique-binary-search-trees-ii/ 题意分析: 给一个整数,返回所有中序遍历是1到n的树. 题目思路: 这可以用递归的思想.首先确定根节点,如果k是根节点,那么1-k-1是左子树,而k+1-n为右子树. 代码(python): # Definition for a binary tree node. # class TreeNode(object): # def __init__(self, x):

[LeetCode]题解(python):096-Unique Binary Search Trees

题目来源: https://leetcode.com/problems/unique-binary-search-trees/ 题意分析: 给定一个整数n,返回所有中序遍历是1到n的树的可能. 题目思路: 这是动态规划的题目.选定了第k个为根节点,那么所有的可能就是ans[k-1] * ans[n -k]其中,ans[i]代表i整数i一共有ans[i]种可能. 代码(python): class Solution(object): def numTrees(self, n): ""&q

[LeetCode]题解(python):057-Insert Interval

题目来源 https://leetcode.com/problems/insert-interval/ Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). You may assume that the intervals were initially sorted according to their start times. Examp

[LeetCode]题解(python):056-Merge Intervals

题目来源 https://leetcode.com/problems/merge-intervals/ Given a collection of intervals, merge all overlapping intervals. For example,Given [1,3],[2,6],[8,10],[15,18],return [1,6],[8,10],[15,18]. 题意分析 Input:a list of intervals Output:a list of intervals

[LeetCode]题解(python):045-Jump game II

题目来源 https://leetcode.com/problems/jump-game-ii/ Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your maximum jump length at that position. Your goal is to re