Word Break II--爆菊之后,便是晴天

题目大意

给定字典和字符串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;
}


你可能感兴趣的:(Word Break II--爆菊之后,便是晴天)