题目一
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
思路
一个字符串能不能满足条件,我们很自然的想法就是:
如果"onetwothree"这一段可以拆分,再加上four如果也可以,那不就行了;
或者
如果"onetwothre"这一段可以拆分,再加上efour如果也可以,那不就行了;
这其实已经抓住了动态规划的最核心的东西了,换成式子来表达,就是
dp["onetwothreefour"] = dp["onetwothree"这一段] && 判断一下"four"
dp["onetwothreefour"] = dp["onetwothre"这一段] && 判断一下"efour"
Code
/*
动态规划算法,dp[i]表示s前i个字符能否拆分
转移方程:dp[j] = dp[i] && check(s[i+1, j]);
check(s[i+1, j])就是判断i+1到j这一段字符是否能够拆分
其实,调整遍历顺序,这等价于s[i+1, j]是否是wordDict中的元素
这个举个例子就很容易理解。
假如wordDict=["apple", "pen", "code"],s = "applepencode";
dp[8] = dp[5] + check("pen")
翻译一下:前八位能否拆分取决于前五位能否拆分,加上五到八位是否属于字典
(注意:i的顺序是从j-1 -> 0哦~
*/
class Solution {
public:
unordered_map<string, bool> map;
bool check(string str) {
return map[str];
}
bool wordBreak(string s, vector<string> &wordDict) {
int size = s.size();
bool dp[size + 1];
memset(dp, false, sizeof(dp));
//构建一个哈希表,方便查询
for (auto str:wordDict) {
map[str] = true;
}
dp[0]=true;
for (int j = 0; j <= size; j++) {
for (int i = j - 1; i >= 0; i--) {
dp[j] = dp[i] && check(s.substr(i, j - i ));
if (dp[j]) break;
}
}
return dp[size];
}
};
Comments | 0 条评论