Word Break--we are coming for peace...

题目大意

给定一个字符串字典和一个字符串s,判断s能否由字典中的单词组成。


思路

本人比较懒,首先就只会想暴力的方法,这里暴力必须是可以得到答案的:使用递归去深度优先搜索每一个可能的截断点,判断两个截断点之间字符构成的字符串是否存在于字典中,代码简单,清晰明了,对于这样的思路和代码,OJ毫不犹豫地赏给了我一个TLE。显然当s足够长的话,栈深度过大,返回的时间就太长,那么能否使用备忘录记录下每一次递归的结果然后直接返回呢?我觉得这样还是不能从根本上解决问题,因此没有尝试,各位有兴趣可以试试。

        上面讲了这么多废话主要是为了告诉大家当今世界需要的是和平而非暴力(也可以是优化后的暴力,深藏功与名)。。。。咳咳,所以这里要用DP来优化时间,设置数组

dp[i][j]表示当前第i次插在第j个位置时j以前的串s'能否由字典中的单词构成,即s[0~j]是否能满足题目要求,那么可以得到状态转移方程dp[i][j] = dp[i-1][0~j-1]  。此方程一出,写代码就问题不大了,这里为了便于理解使用的二维数组,实际上用一维数组解决问题更加清晰和便捷(因为要记录第i-1次的状态)就能解决问题了。复杂度看似是O(n^3),有更好的方法可以留言给我,感谢过路神牛捧场。


补:好吧,下午重新看了一下,发现j那一层循环好像隐含了i的意思,相当于把次数包含进去了。。所以可以把最外层循环删除,复杂度瞬间降到O(N^2),leetcode上30+ms就搞定了,所以dp[j]表示的是s[0~j]是否能被拆分


代码

#include<iostream>
#include<set>
using namespace std;
bool wordBreak(string s, unordered_set<string> &dict) {//要测试的话把这里的unordered_set改成set

     bool dp[1000];
     for (int i = 0; i < s.length(); i ++){
         dp[i] = false;
         if (dict.find(s.substr(0,i+1)) != dict.end())dp[i] = true;
     }
     //for (int i = 1; i < s.length(); i ++){//这个可以删除
         for (int j = 0; j < s.length(); j ++){
             if (dp[j]){
                for (int k = j+1; k < s.length(); k ++){
                    if (dp[k] == false && dict.find(s.substr(j+1, k-j)) != dict.end())dp[k] = true;    
                }                
             }    
         }    
     //}
     return (dp[s.length()-1] == true);
}
int main()
{
	set<string> s;
	//s.insert("fohhemkka");s.insert("ecojceoaejkkoe");s.insert("ecojceoaejkkoed");s.insert("kofhmoh");s.insert("kcjmkggcmnami");s.insert("kcjmkggcmnam");
	
	//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");
	string str;
	cin >> str;
    if(wordBreak(str, s))cout<<"true"<<endl;
    else cout<<"false"<<endl;
    system("pause");
	return 0;
}


你可能感兴趣的:(Word Break--we are coming for peace...)