在DP问题中使用布尔的按位存储

我在this leetcode上工作,我想知道如何使用按位操作。原因是,当我使用lru_cache时,我收到isUsed的错误不可散列。代替isUsed的bool数组,使用int和按位运算代替bool的最佳实践是什么

def canIWin(self,n: int,target: int) -> bool:
    @lru_cache(None)
    def isWin(isUsed,target):
        # print(isUsed,target)
        if target<=0:
            return False
        for i in reversed(range(1,n+1)):
            if not isUsed[i-1]:
                if i>=target:
                    return True
                isUsed[i-1] = True
                if not isWin(isUsed[::],target-i):
                    return True
                isUsed[i-1] = False

        return False

    if target <2:
        return True
    if n*(n+1)/2<target:
        return False
    return isWin([False]*n,target)
jiabing305 回答:在DP问题中使用布尔的按位存储

正如kaya3在其注释中提到的那样,您可以使用元组而不是列表,而不是使用整数位集,因为它们是不可变且可哈希的。在元组中设置一些位会更加复杂,因此一旦您在函数内部,将元组转换为列表可能会更容易。


如果您真的想使用位集,则必须使用2的幂进行一些ANDing,ORing和XORing。

在长度为 n 的位集中的索引 i 处设置位:

bitset = bitset | 2**(n-1-i)

重设一点:

bitset = bitset & (2**n-1) ^ 2**(n-1-i)
,

您可以使用元组或位元组。使用元组的最简单方法是将其转换为数组,然后再转换回它,但是,将值数组切片并传递而不是传递布尔数组更快。

这是三种方法:

  1. 元组切片无布尔数组(388毫秒),这是最快的,因为您可以通过检查最后一项来提早退出
  2. 使用位集(532毫秒)
  3. 从列表转换为元组(624毫秒)

元组切片:

def canIWin(self,n: int,target: int) -> bool:
    @lru_cache(None)
    def isWin(nums,target):
        if target <= 0:
            return False
        n = len(nums)
        if nums[-1] >= target:
            return True
        for i in range(n):
            if not isWin(nums[:i] + nums[i + 1:],target - nums[i]):
                return True
        return False
    if target < 2:
        return True
    if (n + 1) * n / 2 < target:
        return False
    return isWin(tuple(range(1,n + 1)),target)

位集:

def canIWin(self,target: int) -> bool:
    isNthBitSet = lambda x,n: (x & (1 << n) != 0)
    setNthBit = lambda x,n: x | (1 << n)
    @lru_cache(None)
    def isWin(isUsed,target):
        if target <= 0:
            return False
        for i in reversed(range(n)):
            if not isNthBitSet(isUsed,i):
                if not isWin(setNthBit(isUsed,i),target - i - 1):
                return True
    return False
if target < 2:
    return True
if n * (n + 1) / 2 < target:
    return False
return isWin(0,target)

列出元组:

def canIWin(self,target: int) -> bool:
    @lru_cache(None)
    def isWin(isUsed,target):
        isUsed = list(isUsed)
        if target <= 0:
            return False
        for i in reversed(range(1,n + 1)):
            if not isUsed[i - 1]:
                if i >= target:
                    return True
                isUsed[i - 1] = True
                if not isWin(tuple(isUsed[::]),target - i):
                    return True
                isUsed[i - 1] = False
        return False
    if target < 2:
        return True
    if n * (n + 1) / 2 < target:
        return False
    return isWin(tuple([False] * n),target)
本文链接:https://www.f2er.com/3048905.html

大家都在问