We are given N different types of stickers. Each sticker has a lowercase English word on it.
You would like to spell out the giventargetstring by cutting individual letters from your collection of stickers and rearranging them.
You can use each sticker more than once if you want, and you have infinite quantities of each sticker.
What is the minimum number of stickers that you need to spell out thetarget? If the task is impossible, return -1.
Example 1:
Input:
["with", "example", "science"], "thehat"
Output:
3
Explanation:
We can use 2 "with" stickers, and 1 "example" sticker.
After cutting and rearrange the letters of those stickers, we can form the target "thehat".
Also, this is the minimum number of stickers necessary to form the target string.
Example 2:
Input:
Output:
Explanation:
Note:
stickershas length in the range[1, 50].
stickersconsists of lowercase English words (without apostrophes).
targethas length in the range[1, 15], and consists of lowercase English letters.
In all test cases, all words were chosen randomly from the 1000 most common US English words, and the target was chosen as a concatenation of two random words.
The time limit may be more challenging than usual. It is expected that a 50 sticker test case can be solved within 35ms on average.
We can't form the target "basicbasic" from cutting letters from the given stickers.
class Solution {
public int minStickers(String[] stickers, String target) {
if (stickers == null || stickers.length == 0 || target == null || target.length() == 0) {
return 0;
}
int n = target.length();
// We use bitmap to represent each subset, each subset will contains different characters from target
int m = 1 << n;
// dp[i] means the minimum number of stickers we need to get the ith subset
int[] dp = new int[m];
Arrays.fill(dp, Integer.MAX_VALUE);
// Initialize empty subset
dp[0] = 0;
for (int i = 0; i < m; i++) {
// There is no way to construct the a subset starting from the current one, so skip it
if (dp[i] == Integer.MAX_VALUE) continue;
for (String sticker : stickers) {
int curSet = i;
for (char c : sticker.toCharArray()) {
for (int k = 0; k < target.length(); k++) {
// When target contains the current character and the current subset doesn't contain the character
// Add that character and form a new subset
if (c == target.charAt(k) && ((curSet >> k) & 1) == 0) {
curSet |= 1 << k;
break;
}
}
}
// dp[i] + 1 means the using the minimum number of stickers to form subset i and plus one more sticker, since we
// can form current subset from i with one sticker
dp[curSet] = Math.min(dp[curSet], dp[i] + 1);
}
}
return dp[m - 1] == Integer.MAX_VALUE ? -1 : dp[m - 1];
}
}