LeetCode第 140 题:单词拆分 II(C++)

140. 单词拆分 II - 力扣(LeetCode)
在这里插入图片描述

LeetCode第 139 题:单词拆分(C++)_zj-CSDN博客差不多,只不过这儿需要输出详细的dp方案,而且是所有的。

所以在139题的基础上:

  • 循环遍历的时候不能break出去,因为需要所有的组合信息;
  • 增加一个二维数组,记录dp转移的信息
  • 根据二维数组得到的转移信息,dfs生成可能的string
class Solution {
public:
    vector<string>  res;
    string tmp = "";
    void backtrack(string &s, string tmp, vector<vector<int>> &record, int m){
        if(m == s.size()){
            res.push_back(string(tmp.begin(), tmp.end()-1));//去掉最后的空格
            return;
        }
        for(int i = 0; i < record[m].size(); ++i){
            if(record[m][i] == 1){
                backtrack(s, tmp + s.substr(m, i-m) + " ", record, i);
            }
        }
    }
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> wordset;
        unordered_set<int> lenset;
        for(const auto &word : wordDict){
            wordset.insert(word);
            lenset.insert(word.size());
        }    

        vector<vector<int>> record(s.size()+1, vector<int>(s.size()+1, 0));//用于记录可达信息
        vector<int> dp(s.size()+1, 0);
        dp[0] = 1;
        for(int i = 1; i <= s.size(); ++i){
            for(int j = i-1; j >= 0; --j){//枚举i之前的所有位置
                if(!lenset.count(i-j))  continue;//[j,i]长度不合法(没有单词是这个长度)
                if(dp[j] && wordset.count(s.substr(j, i-j))){
                    dp[i] = 1;   //这儿不能break出去了,因为需要计算全部的可能组合
                    record[j][i] = 1;//记录j->i,表示可以从j通过某个单词转移到i
                }
            }
        }
        if(dp.back() == 0)  return res;//末尾并不可达
        backtrack(s, tmp, record, 0);//dfs搜寻所有路径
        return res;
    }
};

不过上面的二维数组记录可达信息可以不用,在回溯里面进行判断也是可以的:

class Solution {
public:
    vector<string> res;
    unordered_set<string> wordset;
    unordered_set<int> lenset;
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        for(const auto &w : wordDict) {
            wordset.insert(w);
            lenset.insert(w.size());
        } 
        vector<int> dp(s.size()+1, 0);
        dp[0] = 1;
        for(int i = 1; i <= s.size(); ++i){
            for(const auto &j : lenset){//遍历所有的单词长度
                if(i >= j && dp[i-j] && wordset.count(s.substr(i-j, j)))    dp[i] = 1;
            }
        }
        //需要事先判断末尾是否可达,很重要!!!
        if(dp.back() == 0)  return res;//末尾不可达
        backtrack(dp, 0, s, "");
        return res;
    }
    //idx代表上一个可达的位置
    void backtrack(vector<int> &dp, int idx, string &s, string tmp){
        if(idx == s.size()){
            tmp.pop_back();//去掉最后的空格
            res.push_back(tmp);
            return;
        }
        //idx为上一个可达位置,初始为0
        for(int i = idx+1; i < dp.size(); ++i){//i最开始为1,对应s的首元素
            if(dp[i] == 1 && wordset.count(s.substr(idx, i-idx))){//可达并且单词存在
                backtrack(dp, i, s, tmp+s.substr(idx, i-idx)+" ");
            }
        }
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值