---
# System prepended metadata

title: 0691. Stickers to Spell Word
tags: [Leetcode, Dynamic Programming, Hard]

---

# 0691. Stickers to Spell Word
###### tags: `Leetcode` `Hard` `Dynamic Programming`
Link: https://leetcode.com/problems/stickers-to-spell-word/
## 思路
状态压缩+背包问题
设置状态数组```dp[i]```,dp的大小是 ```N = 2^n```, dp的索引i的每一个bit表示的是```target```对应位置的字符是否得到了满足。举个例子，n=3时，i=3 (即011)表示```target```的末两位的字符得到了满足，但第一位的字符还没有得到满足。```dp[i]```表示在状态i下，需要的```sticker```的最少数目。

注意：这种状态的排列有一个非常好的性质。任何状态，只可能由位于其前面的状态转移得到，不可能从后面的状态转移得到。比如```i=3```(即 011)这个状态，只可能从```i=0,1,2```转移过来（通过使用某些合适的```sticker```）；再比如```i=4```(即100)这个状态，只可能从```i=0```转移过来。这种状态转移的性质，非常适合dp根据i从前往后的遍历。

所以，dp的大循环就是 ```for (state=0; state<(1<<n); state++)```. 对于该状态```state```，我们尝试每一个```sticker[k]```，计算状态```i```经过```sticker[k]```的帮助后得到的状态```new_state```（注意已经分析过```new_state```肯定是大于```state```的），那么```dp[new_state]```就可以得到更新```dp[new_state]=min(dp[new_state], dp[state]+1)```
## Code
```java=
class Solution {
    public int minStickers(String[] stickers, String target) {
        int n = target.length();
        int[] dp = new int[1<<n];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for(int state=0; state<(1<<n); state++){
            for(String sticker:stickers){
                if(dp[state]==Integer.MAX_VALUE) continue;
                int nextState = getNext(sticker, target, state);
                dp[nextState] = Math.min(dp[nextState], dp[state]+1);
            }
        }
        return dp[(1<<n)-1]==Integer.MAX_VALUE?-1:dp[(1<<n)-1];
    }
    private int getNext(String sticker, String target, int curr){
        for(int i=0; i<sticker.length(); i++){
            char c = sticker.charAt(i);
            for(int j=0; j<target.length(); j++){
                if(target.charAt(j)==c && ((curr>>j)&1)==0){
                    curr += 1<<j;
                    break;
                }
            }
        }
        return curr;
    }
}
```