DFS+回溯专题15 - leetcode464. Can I Win博弈论

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a786150017/article/details/85077259

464. Can I Win

题目描述

2个玩家轮流从1…maxChoosableInteger中最优地选择1个数字。第一个玩家先选,第二个玩家后选,每个人选过的数字之后就不能再选。2个玩家谁先加使得两人总和≥desiredTotal谁就赢。问第一个玩家是否可以赢得比赛?

例子

Input:
maxChoosableInteger = 10
desiredTotal = 11
Output:false

思想
博弈论。
1)如果所有数字和<desiredTotal,肯定不可能赢;如果初始desiredTotal <= 0,记为赢。
2)DFS:表示用户在当前nums和desiredTotal情况下,是否胜利。
如果max(nums) >= desiredTotal,则可以挑选该最大值,获得胜利;
否则,遍历所有可能:只要对方输了,那么就判断用户就赢;遍历所有可能后,都不能赢,则定该用户输了。

解法
TLE

class Solution(object):
    def canIWin(self, maxChoosableInteger, desiredTotal):
        """
        :type maxChoosableInteger: int
        :type desiredTotal: int
        :rtype: bool
        """
        if (1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal:
            return False
        if desiredTotal <= 0:
            return True
        
        visited = '0' * (1 + maxChoosableInteger)
        return self.dfs(maxChoosableInteger, desiredTotal, visited)
    
    def dfs(self, maxChoosableInteger, desiredTotal, visited):
        if desiredTotal <= 0:
            return False
            
        for i in range(1, maxChoosableInteger+1):
            if visited[i] == '0':
                visited = visited[:i] + '1' + visited[i+1:]
                # Another failed, I win
                if not self.dfs(maxChoosableInteger, desiredTotal - i, visited):
                    visited = visited[:i] + '0' + visited[i+1:]    # Mark
                    return True
                visited = visited[:i] + '0' + visited[i+1:]    # Mark
        return False

改进:引入self.cache记录判断过的情况。

class Solution(object):
    def canIWin(self, maxChoosableInteger, desiredTotal):
        """
        :type maxChoosableInteger: int
        :type desiredTotal: int
        :rtype: bool
        """
        if (1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal:
            return False
        if desiredTotal <= 0:
            return True
        
        self.cache = {}
        visited = '0' * (1 + maxChoosableInteger)
        return self.dfs(maxChoosableInteger, desiredTotal, visited)
    
    def dfs(self, maxChoosableInteger, desiredTotal, visited):
        if desiredTotal <= 0:
            return False

        if (desiredTotal, visited) in self.cache:
            return self.cache[(desiredTotal, visited)]
        for i in range(1, maxChoosableInteger+1):
            if visited[i] == '0':
                visited = visited[:i] + '1' + visited[i+1:]
                # Another failed, I win
                if not self.dfs(maxChoosableInteger, desiredTotal - i, visited):
                    visited = visited[:i] + '0' + visited[i+1:]    # Mark
                    self.cache[(desiredTotal, visited)] = True
                    return True
                visited = visited[:i] + '0' + visited[i+1:]    # Mark
        self.cache[(desiredTotal, visited)] = False
        return False

更简洁:不用额外的visited,改变nums。

class Solution(object):
    def canIWin(self, maxChoosableInteger, desiredTotal):
        """
        :type maxChoosableInteger: int
        :type desiredTotal: int
        :rtype: bool
        """
        if (1 + maxChoosableInteger) * maxChoosableInteger / 2 < desiredTotal:
            return False
        if desiredTotal <= 0:
            return True
        
        self.cache = {}
        return self.dfs(tuple(range(1, maxChoosableInteger+1)), desiredTotal)
    
    def dfs(self, nums, desiredTotal):
        if nums in self.cache:
            return self.cache[nums]
        if max(nums) >= desiredTotal:
            self.cache[nums] = True
            return True
        
        self.cache[nums] = False
        for i in range(len(nums)):
            if not self.dfs(nums[:i] + nums[i+1:], desiredTotal - nums[i]):
                self.cache[nums] = True
                return True
        return False

猜你喜欢

转载自blog.csdn.net/a786150017/article/details/85077259