# 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;
}
}
```