691. Stickers to Spell Word

解法

状态压缩DP,从题目条件可以知道target的长度不超过15,所以可以用整数来表示target的哪一位已经被贴纸满足了。
状态state1只可能从比它小的数值state2转化过来,因为state1必然是由state2的某些位从0变1转化而来的
所以DP的时候可以从小到大进行,假如遍历到state的时候:

  1. dp[state]还是初始化的值,那么证明之前的状态都无法到达state,而之后的状态显然也不会到达state,所以state就是一个无法到达的状态,跳过即可。
  2. dp[state]不是初始值,那么我们遍历贴纸数组,找到加一张贴纸可以到达的状态dp[now]dp[now]的值可能是它原来的值,也可能是dp[state]+1

另外,有两个剪枝增加效率的方式:

  1. sticker里跟target无关的字母可以删除
  2. 如果某个sticker有的字母在另一个sticker里都有,那么它可以删除了,因为直接使用后者能达到一样的效果
class Solution(object):
    def minStickers(self, stickers, target):
        """
        :type stickers: List[str]
        :type target: str
        :rtype: int
        """
        from collections import Counter
        n = len(target)
        ns = (1<<n)
        dp = [-1]*ns
        dp[0] = 0
        t_count = Counter(target)
        stickers = map(lambda x:Counter(x) & t_count, stickers)
        i = 0
        while i<len(stickers):
            if any(stickers[i]&stickers[j]==stickers[i] for j in xrange(len(stickers)) if i!=j):
                stickers.pop(i)
                i -= 1
            i += 1

        for state in xrange(ns):
            if dp[state]==-1:
                continue
            for sticker in stickers:
                now = state
                for letter in sticker.elements():
                    for i in xrange(n):
                        if now & (1<<i) == 0 and target[i]==letter:
                            now |= (1<<i)
                            break
                if dp[now]==-1 or dp[now]> dp[state]+1:
                    dp[now] = dp[state]+1

        return dp[ns-1]

猜你喜欢

转载自blog.csdn.net/lemonmillie/article/details/85228013