题目大意
给定字典和字符串s,输出所有能匹配的结果。
思路
同上题,我也想着用个暴力的递归过去,结果又被OJ果断地赏了一个TLE,有一种一天被OJ爆菊两次的蛋蛋忧桑。。。同样用dp优化暴力方法,这次由于要输出每次的匹配结果,因此需要二维数组作为支持,取dp[i][j]表示s字串的第i~j段是否能够在字典中匹配,然后可以得到一个稀疏矩阵(个人观点,应该是比较稀疏的),矩阵保留了每次的匹配信息,然后自顶向下深搜进行字符串的匹配输出,存储到一个vector数组中,用list存储临时结果。最后输出。整个过程没啥特别的难度,正确理解上一题之后应该很容易看懂。值得一提的是此题用了一个有些tricky方法去剪枝,以复杂度O(n^3)水过了leetcode的OJ,具体方法可以在代码中看到,惭愧惭愧,求路过大神帮忙改进和优化。令附上暴力方法,便于理解算法过程,顺便留作纪念。
代码
1、暴力(菊)的递归
class Solution {
public:
list <string> seg;
void recursion(int sum, int len, string s, unordered_set<string> &dict, bool finished, vector<string> &ans){
if (dict.find(s) != dict.end()){
seg.push_back(s);
//cout<<"sum:"<<sum<<"len:"<<len<<"s:"<<s<<endl;
if (sum+s.length() == len){
string per_ans = "";
for (list<string> :: iterator it = seg.begin(); it != seg.end(); it ++){
if (it != seg.begin())per_ans += " ";
per_ans += (*it);
//cout <<"it:"<<*it<<endl;
}
ans.push_back(per_ans);
}
seg.pop_back();
return ;
}
for (int i = 0; i < s.length(); i ++){
string tmp1 = "";
for (int j = 0; j <= i; j ++) tmp1 += s[j];
if (dict.find(tmp1) != dict.end()){
seg.push_back(tmp1);
string tmp2 = "";
int j=0;
for (j = i+1; j < s.length(); j ++) tmp2 += s[j];
//cout<<"tmp1:"<<tmp1<<" sum:"<<sum<<"tmp2:"<<tmp2<<endl;
recursion(sum+tmp1.length(),len,tmp2, dict, finished, ans);
seg.pop_back();
}
}
}
//unordered_set
vector<string> wordBreak(string s, unordered_set<string> &dict) {
vector<string> ans;
ans.clear();
recursion(0, s.length(), s,dict,false,ans);
return ans;
}
};
2 水过去的tricky DP
#include<iostream>
#include<set>
#include<list>
#include<vector>
using namespace std;
list <string> seg;
bool dp[500][500];//存储全部每次匹配的结果,有点暴力,但比起裸递归也有点优化
void recursion(int left, int right, string s, int len, vector<string> &ans)
{
if (right == len-1){
string per_ans = "";
for (list<string> :: iterator it = seg.begin(); it != seg.end(); it ++){
if (it != seg.begin())per_ans += " ";
per_ans += (*it);
//cout <<"it:"<<*it<<endl;
}
ans.push_back(per_ans);
}
for (int i = right+1; i < len; i ++){
if (dp[right+1][i]){
seg.push_back(s.substr(right+1, i-right));
recursion(right+1, i, s, len, ans);
seg.pop_back();
}
}
}
vector<string> wordBreak(string s, unordered_set<string> &dict) {//要测试的话把这里的unordered_set改成set
int len = s.length();
vector<string> ans;
ans.clear();
for (int i = 0; i < len; i ++){
for (int j = 0; j < len; j ++) dp[i][j] = false;
if (dict.find(s.substr(0,i+1)) != dict.end())dp[0][i] = true;
}
for (int i = 0; i < s.length(); i ++){//这个此时不可以删除,因为要记录后续的输出状态
for (int j = 0; j < len; j ++){
if (dp[i][j]){
for (int k = j+1; k < len; k ++){
if (dp[j+1][k] == false && dict.find(s.substr(j+1, k-j)) != dict.end())dp[j+1][k] = true;
}
}
}
}
bool jud = true;//若最终串无法完全被匹配,直接返回空,相当tricky的方法,求改进
for (int i = 0; i < len && jud; i ++){
if (dp[i][len-1])jud = false;
}
if (jud)return ans;
for (int i = 0; i < len; i ++){
if (dp[0][i]){
seg.push_back(s.substr(0,i+1));
recursion(0,i,s,len,ans);
seg.pop_back();
}
}
return ans;
}
int main()
{
set<string> s;
//s.insert("fohhemkka");s.insert("ecojceoaejkkoe");s.insert("ecojceoaejkkoed");s.insert("kofhmoh");s.insert("kcjmkggcmnami");s.insert("kcjmkggcmnam");
//catsanddog
//s.insert("a");s.insert("aa");s.insert("bc");
//s.insert("aaa");s.insert("aaaa");s.insert("aaaaa");s.insert("aaaaaa");s.insert("aaaaaaa");s.insert("aaaaaaaa");s.insert("aaaaaaaaa");s.insert("aaaaaaaaaa");
//s.insert("cat");s.insert("cats");s.insert("and");s.insert("dog");s.insert("sand");
string str;
cin >> str;
vector<string> vc = wordBreak(str,s);
for (vector<string> :: iterator it = vc.begin(); it != vc.end(); it ++){
cout<<(*it)<<endl;
}
system("pause");
return 0;
}