Problem: 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 string `target` 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.

Return the minimum number of stickers that you need to spell out `target`. If
the task is impossible, return `-1`.

Note: In all test cases, all words were chosen randomly from the `1000` most
common US English words, and `target` was chosen as a concatenation of two
random words.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def minStickers(self, stickers: List[str], target: str) -> int:
    maxMask = 1 << len(target)
    dp = [math.inf] * maxMask
    dp[0] = 0

    for mask in range(maxMask):
      if dp[mask] == math.inf:
        continue
      for sticker in stickers:
        superMask = mask
        for c in sticker:
          for i, t in enumerate(target):
            if c == t and not (superMask >> i & 1):
              superMask |= 1 << i
              break
        dp[superMask] = min(dp[superMask], dp[mask] + 1)

    return -1 if dp[-1] == math.inf else dp[-1]


Java solution:
class Solution {
  public int minStickers(String[] stickers, String target) {
    final int n = target.length();
    final int maxMask = 1 << n;
    // dp[i] := the minimum number of stickers to spell out i, where i is the
    // bit mask of target
    int[] dp = new int[maxMask];
    Arrays.fill(dp, Integer.MAX_VALUE);
    dp[0] = 0;

    for (int mask = 0; mask < maxMask; ++mask) {
      if (dp[mask] == Integer.MAX_VALUE)
        continue;
      // Try to expand from `mask` by using each sticker.
      for (final String sticker : stickers) {
        int superMask = mask;
        for (final char c : sticker.toCharArray())
          for (int i = 0; i < n; ++i)
            // Try to apply it on a missing letter.
            if (c == target.charAt(i) && (superMask >> i & 1) == 0) {
              superMask |= 1 << i;
              break;
            }
        dp[superMask] = Math.min(dp[superMask], dp[mask] + 1);
      }
    }

    return dp[maxMask - 1] == Integer.MAX_VALUE ? -1 : dp[maxMask - 1];
  }
}


C++ solution:
class Solution {
 public:
  int minStickers(vector<string>& stickers, string target) {
    const int n = target.size();
    const int maxMask = 1 << n;
    // dp[i] := the minimum number of stickers to spell out i, where i is the
    // bit mask of target
    vector<int> dp(maxMask, INT_MAX);
    dp[0] = 0;

    for (int mask = 0; mask < maxMask; ++mask) {
      if (dp[mask] == INT_MAX)
        continue;
      // Try to expand from `mask` by using each sticker.
      for (const string& sticker : stickers) {
        int superMask = mask;
        for (const char c : sticker)
          for (int i = 0; i < n; ++i)
            // Try to apply it on a missing letter.
            if (c == target[i] && (superMask >> i & 1) == 0) {
              superMask |= 1 << i;
              break;
            }
        dp[superMask] = min(dp[superMask], dp[mask] + 1);
      }
    }

    return dp.back() == INT_MAX ? -1 : dp.back();
  }
};