对于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;
}
};
有人可以帮助我了解它的工作原理吗?我发现这种递归很难执行。
答案 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
循环查看原始字符串的每个子字符串(从索引开始),例如:p
,pi
,pin
,pine
,...,以及当这些子字符串之一在字典中时,请将其放入v
中,并再次调用该方法,从该子字符串结束处的索引处开始。
最后,当递归返回时,我们从v
中删除了子字符串,因为我们想尝试其他字符串。
从提供的解决方案到此解决方案的不同之处在于,提供的解决方案使用动态编程来存储每个子字符串有多少种可能性,因此,如果以前已经计算过solve(a, b)
,则不需要再次计算。对于您来说,扩展并不难。