Word Break Total Accepted: 4925 Total Submissions: 26611 My Submissions
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.
For example, given
s = "leetcode",
dict = ["leet", "code"].
Return true because "leetcode" can be segmented as "leet code".
这个题最先想到就是回溯递归法,主要还是递归了,用回溯是因为最近在练习回溯方法,就用了回溯的框架算法,简单的写了下。
版本1.暴力回溯递归法,一般地,对于字符串,str[t...n]扫描,如果扫描到i,字典中有匹配的,那么递归对str[i+1,n]的字符串进行处理,如果扫描到i,t--i之间的字符串没有匹配的,则继续i++什么也不做。若不做任何剪枝,连一般的数据的都会timeout,所以优化第一步if(dirc.count(subs) && cou == 0)加了一个cou==0,如果搜索到结果了,就不找了,题中只要求是否存在解。
下面的这个算法,就是基本无优化的,所以很难过极限值,你可以提交试试,但对于一步步学习研究很有用啊,基础不好的,不是来就能想到优化策略的,先写出这个,然后慢慢优化。
class Solution {
int cou = 0;
vector<string> ve,re;
string str;
int n;
void BackTrack(int t,unordered_set<string>& dirc,int *a)
{
if(t == n)
{
cou++;
// re = ve;
}else
{
for(int i = t; i < n; i++)
{
string subs = str.substr(t,i-t+1);
//cout << "t " << t << " i " << i << " subs" << subs << endl;
if(dirc.count(subs) && cou == 0)
{
// cout << "t " << t << " subs" << subs << endl;
// ve.push_back(subs);
BackTrack(i+1,dirc,a);
// ve.pop_back();
}
}
}
}
public:
bool wordBreak(string s, unordered_set<string> &dict) {
str = s;
n = str.size();
int *a = new int[n];
for(int i = 0; i < n; i++)
a[i] = 1;
BackTrack(0,dict,a);
delete [] a;
if(cou) return true;
else return false;
}
};
版本2,是加了,记忆化搜索,也即,对于i之前已经匹配的搜索过程中,对于一个j>i,若str[j..end]无解,那么下次就不用搜索这个子字符串了,能直接进行判断,非常省力气。所以这里,添加了一个数组a,用来记录字符串中每一个i,到end,之间的字符串是否可以找到解,如果不能找到,那么下次再次递归到该子字符串时就不用搜索了。 不懂的话,推荐看刘汝佳那本白皮书,acm竞赛入门经典 ,动态规划那一章,讲到有记忆化搜索,非常好用!
下面这两行就是对上面的一个优化,只增加了两个判断,用于剪枝和维护数组a。
if(((i+1) != n && a[i+1]) || i+1 == n)BackTrack(i+1,dirc,a);
if(!cou) a[i+1] = 0;
class Solution {
int cou = 0;
vector<string> ve,re;
string str;
int n;
void BackTrack(int t,unordered_set<string>& dirc,int *a)
{
if(t == n)
{
cou++;
// re = ve;
}else
{
for(int i = t; i < n; i++)
{
string subs = str.substr(t,i-t+1);
//cout << "t " << t << " i " << i << " subs" << subs << endl;
if(dirc.count(subs) && cou == 0)
{
// cout << "t " << t << " subs" << subs << endl;
// ve.push_back(subs);
if(((i+1) != n && a[i+1]) || i+1 == n)BackTrack(i+1,dirc,a);
if(!cou) a[i+1] = 0;
// ve.pop_back();
}
}
}
}
public:
bool wordBreak(string s, unordered_set<string> &dict) {
str = s;
n = str.size();
int *a = new int[n];
for(int i = 0; i < n; i++)
a[i] = 1;
BackTrack(0,dict,a);
delete [] a;
if(cou) return true;
else return false;
}
};
3,本地测试整个文件代码
#include<iostream>
#include<string>
#include<vector>
#include<cstdlib>
#include<set>
using namespace std;
int cou;
vector<string> ve,re;
string str;
int n;
int a[10];
void BackTrack(int t,set<string>& dirc)
{
if(t == n)
{
cou++;
re = ve;
}else
{
for(int i = t; i < n; i++)
{
string subs = str.substr(t,i-t+1);
cout << "t " << t << " i " << i << " subs" << subs << endl;
if(dirc.count(subs))
{
cout << "t " << t << " subs" << subs << endl;
ve.push_back(subs);
if(a[i+1])BackTrack(i+1,dirc);
if(!cou)a[i+1] = 0;
ve.pop_back();
}
}
}
}
int main()
{
string s[] = {"a"};
set<string> dirc(s,s+1);
str = "a";
n = str.size();
for(int i = 0; i < 10; i++)
a[i] = 1;
BackTrack(0,dirc);
for(vector<string>::iterator it = re.begin(); it != re.end(); it++)
{
cout << *it << " ";
}
cout << "cou " << cou << endl;
system("pause");
return 0;
}