Leetcode: 1434. Number of Ways to Wear Different Hats to Each Other

Descpition

There are n people and 40 types of hats labeled from 1 to 40.
Given a list of list of integers hats, where hats[i] is a list of all hats preferred by the i-th person.
Return the number of ways that the n people wear different hats to each other.
Since the answer may be too large, return it modulo 10^9 + 7.

Example

Input: hats = [[1,2,3],[2,3,5,6],[1,3,7,9],[1,8,9],[2,5,7]]
Output: 111

Note

n == hats.length
1 <= n <= 10
1 <= hats[i].length <= 40
1 <= hats[i][j] <= 40
hats[i] contains a list of unique integers.

分析

     本题需要用状态压缩来实现,一开始希望用 dict 来存储状态以减少存储空间和计算次数。但是事与愿违。
后面改用数组来做存储

code

TLE 版本

class Solution(object):
    def _do(self, hats):
        hat = 0
        for i in hats:
            for j in i:
                hat |= (1<<(j-1))

        dp = [{} for _ in range(len(hats))]
        bitS = lambda x: 1 << (x-1)

        for v in hats[0]:
            dp[0][hat ^ bitS(v)] = 1

        for level in range(1, len(hats)):  # 每次都会计算满足 people[i] 帽子方案,等所有 people 都有帽子戴后返回所有值
           for v in hats[level]:
               for k in dp[level-1]:
                   t, nb = k & bitS(v), k ^ bitS(v)
                   if t == 0:
                       continue
                   dp[level][nb] = (dp[level].get(nb, 0) + dp[level-1][k])%1000000007
         
        return sum([i for i in dp[-1].values()])%1000000007

    def do(self, hats):
        print(self._do(hats))


if __name__ == '__main__':
    s = Solution()
AC 版本
class Solution(object):
    def _do(self, hats):
        hat_set, hat_sorted = set(), []
        for i, v in enumerate(hats):
            hat_set |= set(v)

        hat_sorted = sorted(list(hat_set))
        dp = [[0 for _ in range(0, 1<<len(hats))] for _ in range(len(hat_sorted))]

        bitS = lambda x: 1 << (x-1)

        for i, v in enumerate(hats):
            if hat_sorted[0] in v:
                dp[0][bitS(i+1)] = 1

        for level in range(1, len(hat_sorted)):  # 每次都会计算 hat_sorted[i] 已经满足了哪些人的戴帽子需求
            for person in range(0, len(hats)):
                if hat_sorted[level] not in hats[person]:
                    continue

                dp[level][bitS(person+1)] = 1

                for i, v in enumerate(dp[level-1]):
                    if i & bitS(person+1) != 0:
                        continue
                    dp[level][i | bitS(person+1)] += v

            for i, v in enumerate(dp[level-1]):  # 不用当前帽子时的方案
                dp[level][i] += dp[level-1][i]
        return dp

    def do(self, hats):
        print(self._do(hats))


if __name__ == '__main__':
    s = Solution()
    s.do([[3,2,1],[2,3]])

总结

  • 思路很简单,就是一道普通的状态压缩 dp。但是选择不用的事物作为 dp 压缩会有很大不同的结果
Runtime: 472 ms, faster than 54.46% of Python online submissions for Number of Ways to Wear Different Hats to Each Other.
Memory Usage: 13.7 MB, less than 61.46% of Python online submissions for Number of Ways to Wear Different Hats to Each Other.
原文地址:https://www.cnblogs.com/tmortred/p/13191383.html