leetcode -- 691. Stickers to Spell Word【动态规划 + 位图使用】

来源:互联网 发布:淘宝买家皇冠号多少钱 编辑:程序博客网 时间:2024/06/07 14:56

题目

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.

    题意

    给定一个字符串集合S,以及一个目标字符串T.求使用S中字符串的最小个数,能够满足T需要的字符数。类似于多目标优化的问题(弄清这一类问题如何求解)
    背包问题(变形)
    给定物品的特点
    给定背包的限制
    求最小的物品的数量。

    分析及解答

    参考:(https://discuss.leetcode.com/topic/106368/rewrite-of-contest-winner-s-solution/7)
    • 位图法】因为待匹配串target的数量最多是15个,因此其子集的数量最多有 2^15个,而int类型占用四个字节,能够容纳标识所有target的子集。所以我们可以将target的子集 映射到 int的整型数中。
    • 【int 与 target子集之间的映射关系】将int类型分解为二进制的形式后,有些位置为0,有些位置为1.表明在target中哪些位置的字符是否保留(1表示保留)。
    • 动态规划】dp中存储的是得到子集i,需要的最少的单词的数量。
    class Solution {    public int minStickers(String[] stickers, String target) {        int n = target.length(), m = 1 << n; // if target has n chars, there will be m=2^n-1 subset of characters in target        int[] dp = new int[m];        for (int i = 0; i < m; i++) dp[i] = Integer.MAX_VALUE; // use index 0 - 2^n-1 as bitmaps to represent each subset of all chars in target        dp[0] = 0; // first thing we know is : dp[empty set] requires 0 stickers,        for (int i = 0; i < m; i++) { // for every subset i, start from 000...000。(起点这里很重要,因为大的集合往往依赖于小的集合)            if (dp[i] == Integer.MAX_VALUE) continue;            for (String s : stickers) { // try use each sticker as an char provider to populate 1 of its superset, to do that:                int sup = i;//关键代码(下面:在i上面加入一个单词后的效果)                for (char c : s.toCharArray()) { // for each char in the sticker, try apply it on a missing char in the subset of target                    for (int r = 0; r < n; r++) {                        if (target.charAt(r) == c && ((sup >> r) & 1) == 0) {  //如果target中包含字符c , 并且sup中相应位置没有c。                            sup |= 1 << r;//在sup中相应位置,加入c,形成新的集合。                            break;                        }                    }                }               // after you apply all possible chars in a sticker, you get an superset that take 1 extra sticker than subset               // would take, so you can try to update the superset's minsticker number with dp[sub]+1;                dp[sup] = Math.min(dp[sup], dp[i] + 1);//判断是否需要替换原来sup中的值。            }        }        return dp[m - 1] != Integer.MAX_VALUE ? dp[m - 1] : -1;    }}


  • 原创粉丝点击