LeetCode 139:单词拆分

本文介绍两种实现字符串拆分(word break)的有效算法:循环递推和记忆化递归。通过使用unordered_set快速查找字典中的单词,算法判断输入字符串是否能被字典中的单词完全覆盖。循环递推算法采用动态规划,而记忆化递归则避免重复计算,提高效率。

方法一:循环递推的方式 

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> dict(wordDict.cbegin(), wordDict.cend());
        int n = s.length();
        vector<int> f(n+1, 0); //使用了padding技巧,索引0-n
        f[0] = 1;
        s = " " + s; //漏掉了这一部分,导致后面取s.substr时总是多扣了一位字符,因此结果不对

        for(int i=1; i<=n; ++i) {
            for(int j=0; j<=i; ++j) {
                if(f[j]==1) {
                    string new_str = s.substr(j+1, i-(j+1)+1); //取可分割点之后的部分
                    if(dict.count(new_str)) {
                        f[i] = 1; //dict中可以找得到后面这一段,就说明s前i个字符可以完全 word break
                        break;
                    }
                }
            }
        }
        return f[n];
    }
};

方法二:记忆化的递归

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> dict(wordDict.cbegin(), wordDict.cend());
        return wordBreak(s, dict);
    }

private:
    //vector<int> f(n, -1);
    unordered_map<string, bool> mem_;
    bool wordBreak(string& s, unordered_set<string>& dict) {
        //if(mem_[s]) return ture; //true or false都应该返回
        //递归的终止条件:已经有结果了/在dict中存在
        if(mem_.count(s)) return mem_[s];
        if(dict.count(s)) return mem_[s] = true;
        //if(s == " ") return true;

        for(int i=1; i<s.length(); i++) {
            string left = s.substr(0, i); //从index=0开始,长为i的子串
            string right = s.substr(i); //从index=i开始的子串
            if(dict.count(right) && wordBreak(left, dict)) { //利用&&的短路效应,递归在后,可以节省时间
                return mem_[s] = true; //bug:没有把结果更新到‘记忆’中
            }
        }
        return mem_[s] = false; //bug:没有把结果更新到‘记忆’中
    }
};

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值