zoukankan      html  css  js  c++  java
  • [Leetcode]691.Stickers to Spell Word

    链接:LeetCode691

    给出了 N 种不同类型的贴纸。每个贴纸上都有一个小写的英文单词。
    你希望从自己的贴纸集合中裁剪单个字母并重新排列它们,从而拼写出给定的目标字符串 target。如果你愿意的话,你可以不止一次地使用每一张贴纸,而且每一张贴纸的数量都是无限的。拼出目标 target 所需的最小贴纸数量是多少?如果任务不可能,则返回 -1。

    示例 1:

    输入:

    ["with", "example", "science"], "thehat"
    输出:

    3
    解释:

    我们可以使用 2 个 "with" 贴纸,和 1 个 "example" 贴纸。
    把贴纸上的字母剪下来并重新排列后,就可以形成目标 “thehat“ 了。
    此外,这是形成目标字符串所需的最小贴纸数量。

    相关标签:备忘录+回溯

    这道题也可以看成是背包问题的变形题,在背包问题中我们要求总价值最大,而这里我们要求每个字符被用完。比较简单的做法是利用回溯方法,通过备忘录记住每个字符串的最小贴纸数量,防止出现重复遍历。
    需要注意的是,为了判断目标字符串用掉一个贴纸后的情况,我们可以将字符串转化为26位的数组(因为是a-z的字符,且都为小写字母,这是一种常用节省内存的做法),对数组进行“按位减”。
    另外,可以利用当该贴纸没有字符串出现的第一个字符即进行抛弃等trick,进行剪枝。

    其代码如下:

    python:

    class Solution:
        def minStickers(self, stickers: List[str], target: str) -> int:
            n = len(stickers)
            dic = {'':0}
            count = [self.getCounter(sticker) for sticker in stickers]
            res = self.dfs(count,target,dic)
            return res if res!=float('inf') else -1
    
        def dfs(self,count,target,dic):
            if target in dic:
                return dic[target]
            tar = self.getCounter(target)
            dic[target]  = float('inf')
            for i in range(len(count)):
                if count[i][ord(target[0])-ord('a')]==0:continue
                rest = ''
                for j in range(26):
                    if tar[j] - count[i][j] > 0:
                        rest += chr(ord('a')+j) * (tar[j] - count[i][j])
                dic[target] = min(dic[target],1+self.dfs(count,rest,dic))
            return dic[target]
    
        def getCounter(self,s):
            res = [0 for _ in range(26)]
            for ch in s:
                res[ord(ch)-ord('a')]+=1
            return res
    

    C++:

    class Solution {
    public:
        int minStickers(vector<string>& stickers, string target) {
            int n = stickers.size();
            vector<vector<int>> count(n,vector<int>(26,0));
            for(int i=0;i<n;++i){
                for(char ch:stickers[i]){
                    count[i][ch-'a']++;
                }
            }
            unordered_map<string,int> mp;
            mp[""]=0;
            return dfs(count,target,mp);
        }
    
        int dfs(vector<vector<int>> &count,string target,unordered_map<string,int> &mp){
            if(mp.count(target)) {
                return mp[target];
            }
            vector<int> tar(26,0);
            for(char ch:target){
                tar[ch-'a']++;
            }
            mp[target] = INT_MAX;
            for(int i=0;i<count.size();++i){
                if(count[i][target[0]-'a'] == 0){
                    continue;
                }
                string rest = "";
                for(int j=0;j<26;++j){
                    if(tar[j]-count[i][j]>0){
                        rest += string(tar[j]-count[i][j],'a'+j);
                    }
                }
                int rest_res = dfs(count,rest,mp);
                if (rest_res != -1) {
                mp[target] = min(mp[target],1+rest_res);
                }
            }
            mp[target] = (mp[target]==INT_MAX?-1:mp[target]);
            return mp[target];
        }
    
    };
    

    参考:LeetCode 贴纸拼词(回溯法+备忘录)

  • 相关阅读:
    AdvStringGrid 复选框、goRowSelect
    AdvStringGrid 列宽度、列移动、行高度、自动调节
    AdvStringGrid 滚动条问题
    AdvStringGrid 标题头
    常量的 访问限制
    我自己的方法、组件、属性、变量、常量、数据库常用操作命名方法。
    泛型 for to/in 遍历 PK 效率;TEnumerator、TEnumerable
    Hadoop关键任务Job资源隔离方案
    Hadoop动态调整Map Task内存资源大小
    Hadoop动态调整Map Task内存资源大小
  • 原文地址:https://www.cnblogs.com/hellojamest/p/12285126.html
Copyright © 2011-2022 走看看