程序员面试金典 17.13

Re-Space:给定一个字典和一个句子,根据字典将句子进行拆分,使得最终不在字典中的字母数量最少。

最近刷的比较慢,一是因为白天实习没什么功夫,二是因为书上的解法也可能过不了了,三是题确实难了,光凭打印调试效率太低了,看来应该是不能白板写代码了。

最暴力的方法就是依次尝试在每个可能的地方进行拆分,并在所有的可能中选取最优解,时间复杂度为O(2 ^ n)n为句子sentence的长度,从输入数据规模来看,会达到2 ^ 1000,所以需要通过剪枝和记忆化的搜索来进行优化。剪枝的方法就是在拆分的过程中就计算已经拆分好的部分的无效字符数量。虽然通过了所有的71个测试用例,但是依然超时了,但是当我把dict的类型从set<string>换成unordered_set<string>后就过了,我只能说太蠢了。

class Solution {
private:
    unordered_set<string> dict;
    vector<int> Mem;
    int respace(const string &sentence, int idx)
    {
        if(idx == static_cast<int>(sentence.size())) return 0;
        if(Mem[idx] != INT_MAX) return Mem[idx];
        string part;
        int best = INT_MAX;
        for(int i = idx; i < static_cast<int>(sentence.size()); i++)
        {
            part.push_back(sentence[i]);
            int invalid = dict.find(part) != dict.end() ? 0 : part.size();
            if(invalid < best){
                int RestInvalid = respace(sentence, i + 1);
                if(invalid + RestInvalid < best){
                    best = invalid + RestInvalid;
                }
            }
        }
        Mem[idx] = best;
        return Mem[idx];
    }
public:
    int respace(vector<string> &dictionary, string sentence) {
        if(sentence.empty()) return 0;
        for(const string &word : dictionary)
        {
            dict.insert(word);
        }
        Mem.assign(sentence.size(), INT_MAX);
        respace(sentence, 0);
        return Mem[0];
    }
};

上面的解法需要在确定所有拆分的位置后,才能计算sentence的总无效值,但是由于进行了剪枝优化,在递归的过程中就计算了部分的无效值。更好的方法是在每考察sentence中的一个字符时,就计算当前整体的最优值,类似背包问题,每当加入一个字符时,尝试将该字符作为所有字串的末尾,计算得到一个最小的无效值。

class Solution {
private:
    unordered_set<string> dict;
public:
    int respace(vector<string>& dictionary, string sentence) {
        if(sentence.empty()) return 0;
        for(const string &word : dictionary)
        {
            dict.insert(word);
        }
        vector<int> Invalid(1, 0);
        for(size_t i = 1; i <= sentence.size(); i++)
        {
            Invalid.push_back(Invalid.back() + 1);
            for(const string &word : dict)
            {
                size_t len = word.size();
                if(len <= i && word == sentence.substr(i - len, len)){
                    if(Invalid[i - len] < Invalid[i]){
                        Invalid[i] = Invalid[i - len];
                    }
                }
            }
        }
        return Invalid.back();
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值