题目大意
给定字典和字符串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; } };
#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; }