## 691. Stickers to Spell Word

We are given N different types of stickers. Each sticker has a lowercase English word on it.

You would like to spell out the given `target` string 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 the `target`? 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:

```["notice", "possible"], "basicbasic"
```

Output:

```-1
```

Explanation:

```We can't form the target "basicbasic" from cutting letters from the given stickers.
```

Note:

• `stickers` has length in the range `[1, 50]`.
• `stickers` consists of lowercase English words (without apostrophes).
• `target` has 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.

• b'
\n\n\n

\n

Intuition

\n

A natural answer is to exhaustively search combinations of stickers. Because the data is randomized, there are many heuristics available to us that will make this faster.

\n
\n
• \n

For all stickers, we can ignore any letters that are not in the target word.

\n
• \n
• \n

When our candidate answer won\'t be smaller than an answer we have already found, we can stop searching this path.

\n
• \n
• \n

We should try to have our exhaustive search bound the answer as soon as possible, so the effect described in the above point happens more often.

\n
• \n
• \n

When a sticker dominates another, we shouldn\'t include the dominated sticker in our sticker collection. [Here, we say a sticker `A` dominates `B` if `A.count(letter) >= B.count(letter)` for all letters.]

\n
• \n
\n

\n

Algorithm

\n

Firstly, for each sticker, let\'s create a count of that sticker (a mapping `letter -> sticker.count(letter)`) that does not consider letters not in the target word. Let `A` be an array of these counts. Also, let\'s create `t_count`, a count of our `target` word.

\n

Secondly, let\'s remove dominated stickers. Because dominance is a transitive relation, we only need to check if a sticker is not dominated by any other sticker once - the ones that aren\'t dominated are included in our collection.

\n

We are now ready to begin our exhaustive search. A call to `search(ans)` denotes that we want to decide the minimum number of stickers we can used in `A` to satisfy the target count `t_count`. `ans` will store the currently formed answer, and `best` will store the current best answer.

\n

If our current answer can\'t beat our current best answer, we should stop searching. Also, if there are no stickers left and our target is satisfied, we should update our answer.

\n

Otherwise, we want to know the maximum number of this sticker we can use. For example, if this sticker is `\'abb\'` and our target is `\'aaabbbbccccc\'`, then we could use a maximum of 3 stickers. This is the maximum of `math.ceil(target.count(letter) / sticker.count(letter))`, taken over all `letter`s in `sticker`. Let\'s call this quantity `used`.

\n

After, for the sticker we are currently considering, we try to use `used` of them, then `used - 1`, `used - 2` and so on. The reason we do it in this order is so that we can arrive at a value for `best` more quickly, which will stop other branches of our exhaustive search from continuing.

\n

The Python version of this solution showcases using `collections.Counter` as a way to simplify some code sections, whereas the Java solution sticks to arrays.

\n\n

\n

Complexity Analysis

\n
\n
• \n

Time Complexity: Let be the number of stickers, and be the number of letters in the target word. A bound for time complexity is : for each sticker, we\'ll have to try using it up to times, and updating our target count costs , which we do up to times. Alternatively, since the answer is bounded at , we can prove that we can only search up to times. This would be .

\n
• \n
• \n

Space Complexity: , to store `stickersCount`, `targetCount`, and handle the recursive callstack when calling `search`.

\n
• \n
\n

\n
\n

#### Approach 2: Dynamic Programming

\n

\n

Intuition

\n

Suppose we need `dp[state]` stickers to satisfy all `target[i]`\'s for which the `i`-th bit of `state` is set. We would like to know `dp[(1 << len(target)) - 1]`.

\n

\n

Algorithm

\n

For each `state`, let\'s work with it as `now` and look at what happens to it after applying a sticker. For each letter in the sticker that can satisfy an unset bit of `state`, we set the bit (`now |= 1 << i`). At the end, we know `now` is the result of applying that sticker to `state`, and we update our `dp` appropriately.

\n

When using Python, we will need some extra techniques from Approach #1 to pass in time.

\n\n

\n

Complexity Analysis

\n
\n
• \n

Time Complexity: where be the total number of letters in all stickers, and be the number of letters in the target word. We can examine each loop carefully to arrive at this conclusion.

\n
• \n
• \n

Space Complexity: , the space used by `dp`.

\n
• \n
\n

\n
\n

Analysis written by: @awice. Approach #2 inspired by @dreamoon.

\n
'