难以理解的Leetcode 140解决方案

时间:2020-07-30 20:34:27

标签: c++ algorithm recursion dynamic-programming

对于LeetCode https://leetcode.com/problems/word-break-ii/中的这个问题,我已经看到了下一个解决方案:

class Solution {
private:
    unordered_map<string, vector<string>> dp;
public:
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        if(dp.find(s) != dp.end())
            return dp[s];
        vector<string> result;
        for(string w : wordDict)
        {
            if(s.substr(0, w.length()) == w)
            {
                if(w.length() == s.length())
                    result.push_back(w);
                else
                {
                    vector<string> temp = wordBreak(s.substr(w.length()), wordDict);
                    for(string t : temp)
                        result.push_back(w + " " + t);
                }
            }
        }
        dp[s] = result;
        return result;
    }
};

有人可以帮助我了解它的工作原理吗?我发现这种递归很难执行。

1 个答案:

答案 0 :(得分:2)

这应该更容易理解:

#include <bits/stdc++.h>
using namespace std;

string s = "pineapplepenapple";
int n;
unordered_set<string> dict({"apple", "pen", "applepen", "pine", "pineapple"});

void solve(vector<string> &v, int index = 0){
    if(index >= n){
        for(int i = 0; i < v.size(); i++){
            cout<<v[i]<<" ";
        }
        cout<<endl;
        return;
    }
    for(int i = index; i < n; i++){
        string sub = s.substr(index, i - index + 1);
        if(dict.find(sub) != dict.end()){
            v.push_back(sub);
            solve(v, i + 1);
            v.pop_back();
        }
    }
}

int main(){
    vector<string> v;
    n = s.size();
    solve(v);
    return 0;
}

输出

pine apple pen apple 
pine applepen apple 
pineapple pen apple 

我将分崩离析solve来更好地解释它。

void solve(vector<string> &v, int index = 0){

v存储每个有效单词,以便最后打印。 index是我们目前正在寻找的字符。

    if(index >= n){
        for(int i = 0; i < v.size(); i++){
            cout<<v[i]<<" ";
        }
        cout<<endl;
        return;
    }

这是递归的基本情况,当索引大于或等于字符串本身的大小时,意味着它到达了字符串的结尾。

    for(int i = index; i < n; i++){
        string sub = s.substr(index, i - index + 1);
        if(dict.find(sub) != dict.end()){
            v.push_back(sub);
            solve(v, i + 1);
            v.pop_back();
        }
    }
}

for循环查看原始字符串的每个子字符串(从索引开始),例如:ppipinpine ,...,以及当这些子字符串之一在字典中时,请将其放入v中,并再次调用该方法,从该子字符串结束处的索引处开始。

最后,当递归返回时,我们从v中删除了子字符串,因为我们想尝试其他字符串。

从提供的解决方案到此解决方案的不同之处在于,提供的解决方案使用动态编程来存储每个子字符串有多少种可能性,因此,如果以前已经计算过solve(a, b),则不需要再次计算。对于您来说,扩展并不难。