【LeetCode 每日一题】1255. 得分最高的单词集合(hard)

1255. 得分最高的单词集合


乍一看觉得应该贪心,但是第二个样例就打脸了。 z z z作为贡献最大的字母, x x x z xxxz xxxz却不是得分最高的方案。再一看数据量,单词数小于14,那直接上DFS。

DFS

我们先统计每个字母的数量,然后模拟所有情况,即每个单词选与不选,一共 2 n 2^{n} 2n,用一个变量记录最高得分,每次遍历完所有单词的时候更新最高分,并返回。同时,每次剩余字母数不足以组成一个单词的时候也返回。

class Solution {
public:
    int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score) {
        int ans=0;
        int len=words.size();
        vector<int> ch(30,0);//记录26个字母的数量
        for(auto c:letters){
            ch[c-'a']++;
        }

        function<void(int, int)> dfs=[&](int index, int sum){
            if(index>=len) {//所有单词都已走完,更新最高分
                ans=max(ans,sum);
                return;
            }
            dfs(index+1,sum);//不选当前单词,直接进入下一层
            bool flag=true;
            for(auto c:words[index]){//选中当前单词,减去这些字母,并加上该单词的分数
                ch[c-'a']--;
                sum+=score[c-'a'];
                if(ch[c-'a']<0) flag=false;
            }
            if(flag) dfs(index+1,sum);//如果字母够用,进入下一层
            for(auto c:words[index]){//字母不够用,加回用掉的字母
                ch[c-'a']++;
            }
        };
        dfs(0,0);
        return ans;
    }
};

状态压缩

看了题解发现有更容易理解的方法,就是用二进制去记录单词是否选中,顾名思义状态压缩。两个方法的解题思路是一样的,不同之处在于,状态压缩不需要恢复现场,只需要统计每一个方案所需字母数,与持有的字母数作比较即可知道方案的可行性。

class Solution {
public:
    int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score) {
        vector<int> count(30,0);
        int ans=0;
        int len=words.size();
        for(auto letter:letters){
            count[letter-'a']++;
        }
        for(int i=1;i<(1<<len);i++){
            int sum=0;
            vector<int> now_count(30,0);
            for(int j=0;j<len;j++){
                if(i&(1<<j)){
                    for(auto c:words[j]){
                        now_count[c-'a']++;
                    }
                }
            }
            bool flag=true;
            for(int j=0;j<26;j++){
                sum+=score[j]*now_count[j];
                flag=flag&&(now_count[j]<=count[j]);
            }
            if(flag){
                ans=max(ans,sum);
            }
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值