1.单词拆分
给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:拆分时可以重复使用字典中的单词;你可以假设字典中没有重复的单词。
考察知识点:动态规划
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> dp(s.size()+1,false);
dp[0]=true;
for(int i=1;i<=s.size();++i) //i为子串结束位置
{
for(int j=0;j<i;++j) //j为子串开始位置
{
if(dp[j]&&find(wordDict.begin(),wordDict.end(),s.substr(j,i-j))!=wordDict.end())
{
dp[i]=true;
break;
}
}
}
return dp[s.size()];
}
};
vector改为unordered_set会快一些:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> m(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size()+1,false);
dp[0]=true;
for(int i=1;i<=s.size();++i)
{
for(int j=0;j<i;++j)
{
if(dp[j]&&m.find(s.substr(j,i-j))!=m.end())
{
dp[i]=true;
break;
}
}
}
return dp[s.size()];
}
};
可以进一步优化:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> m(wordDict.begin(), wordDict.end());
vector<bool> dp(s.size()+1,false);
dp[0]=true;
int minlen = INT_MAX, maxlen = INT_MIN;
for (auto & word : wordDict)
{
minlen = min(minlen, (int)word.size()); //子串最小长度
maxlen = max(maxlen, (int)word.size()); //子串最大长度
}
for (int i = minlen; i <= s.size(); ++i)
{
for (int j = max(i - maxlen, 0); j <= i - minlen; ++j)
{
if(dp[j]&&m.find(s.substr(j,i-j))!=m.end())
{
dp[i]=true;
break;
}
}
}
return dp[s.size()];
}
};
2.单词拆分 II
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:分隔时可以重复使用字典中的单词;你可以假设字典中没有重复的单词。
考察知识点:DFS
class Solution {
public:
vector<string> wordBreak(string s, vector<string>& wordDict) {
return dfs(s,wordDict);
}
vector<string> dfs(string s,vector<string>& wordDict){
if(!s.size()) return{""}; //*
vector<string> ans;
for(string word:wordDict)
{
if(word!=s.substr(0,word.size()))
continue;
vector<string> vec=dfs(s.substr(word.size()),wordDict);
for(string str:vec)
ans.push_back(word+(str.size()?" "+str:"")); //*
}
return ans;
}
};