LeetCode 139, 140. Word Break I+II

方法一:Backtracing+Memoization

遇到在wordlist里的单词就继续深搜,memo[i] 用来保存下标i开始到结束的字符串是否能拆分,如果之前保存过,就直接返回,不用重复计算。

用start记录开始的下标,这样就不用传字符串作为参数了,当然用字符串也可以。

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
        vector<int> memo(s.size(),-1);
        return dfs(s,0,wordSet,memo);
    }
    
    bool dfs(string s, int start, unordered_set<string> &wordSet, vector<int> &memo){
        if (start==s.size()) return true;
        if (memo[start]!=-1) return memo[start];
        for (int i=start+1;i<=s.size();++i){
            if (wordSet.count(s.substr(start, i-start)) && dfs(s, i, wordSet, memo)) { // [start,i-1] [i,..] 
                return memo[start] = 1;
            }
        }
        return memo[start] = 0;
    }
};

如果不用memorization,时间复杂度为 O(2^n)。

用了memorization,时间复杂度 O(n^2),

空间复杂度 O(n),递归深度最多为n。

关于memorization的时间复杂度:

For solution 2, please check whether my thought process for getting time complexity is correct or not.
If we don't use memorization the recurrence relation of time complexity will be :
T(n) = T(n-1) + T(n-2) + T(n-3) + .... + T(1)
Now if we add memorization, by the time we finish doing T(n-1), We already have the memorization result for n - 2, n - 3 ... 1.
So to check if T(n-2) is valid only takes O(1) time, same goes for the T(n-3) .....T(1)
The recurrence relation now becomes T(n) = T(n-1) + n - 2
Since we are considering big-O notation, we can drop the constant term, it now becomes T(n) = T(n-1) + n.
Using master theorem, we can easily get the time complexity for this time recurrence relation is O(n^2).

https://stackoverflow.com/questions/21273505/memoization-algorithm-time-complexity

 

方法二:DP

dp[i] 表示前i个字符是否能够被拆分,目标dp[n]

base case: dp[0]=true,可以把wordDict里的元素都置为true

注意本题dp[i]不是表示为下标0~i是有原因的,如果这样表示当然也可以,都需要进行修改,且较为麻烦。因此做dp问题的时候要想一想怎样比较容易写。

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> a;
        for (string word:wordDict)
            a.insert(word);
        
        vector<bool> dp(s.size()+1,false); // dp[i]  前i个元素是否能拆分 0~i-1
        dp[0] = true;
        
        for (int i=1;i<=s.size();++i){
            for (int j=i-1;j>=0;--j){ // 0~j-1  j~i-1
                if (dp[j] && a.count(s.substr(j,i-j))){
                    dp[i] = true;
                    break;
                }
            }
        }return dp[s.size()];
    }
};

时间复杂度 O(n^2)

空间复杂度 O(n)

 

方法三:BFS

这道题也可以bfs来做,和jump game类似,能到字符串最后说明可以拆分。

=========================================================

 

Word Break II

方法一:Backtracing+Memoization

class Solution {
public:
    unordered_map<int,vector<string>> memo; // start -> vector<string>
    
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
        return dfs(s,0,wordSet);
    }
    
    vector<string> dfs(string s, int start, unordered_set<string> &wordSet){
        if (memo.count(start)) return memo[start];
        
        vector<string> res;
        if (start==s.size()) 
            res.push_back("");
        
        for (int i=start+1;i<=s.size();++i){
            if (wordSet.count(s.substr(start, i-start))) { // [start,i-1] [i,..] 
                vector<string> tmp=dfs(s, i, wordSet);
                for (string str:tmp){
                    res.push_back(s.substr(start, i-start) + (str==""?"":" ") + str);
                }     
            }
        }
        memo[start] = res;
        return res;
    }
};

时间复杂度 O(n^3)

空间复杂度 O(n^3)  vector<string> 需要O(n^2) 

  

方法二:DP

思路一样,只不过dp[i]里面保存,能够组成前i个的 用来拼接的word。不过这种方法空间上会超时,没法AC。

class Solution {
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> a;
        for (string word:wordDict)
            a.insert(word);
        
        vector<vector<string>> dp(s.size()+1);
        dp[0].push_back("");
        for (int i=1;i<=s.size();++i){
            for (int j=i-1;j>=0;--j){
                if (dp[j].size()!=0 && a.count(s.substr(j,i-j))){
                    for (string x:dp[j]){
                        dp[i].push_back(x + (x==""?"":" ") + s.substr(j,i-j));
                    }
                }
            }
        }
        return dp[s.size()];
    }
};

时间复杂度 O(n^3)  两层循环n^2,每次循环把数组元素加到dp[i],O(n)

空间复杂度 O(n^3)

 

转载于:https://www.cnblogs.com/hankunyan/p/9385356.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值