题目描述
给定一个字符串,和一个词典dict, 确定s是否可以根据词典中的词分成一个或多个单词.
举个例子:
比如, 给定
s = “leetcode”
dict = [“leet”, “code”]
返回true, 因为"leetcode"可以被分成"leet"和"code"
方法
动态规划
首先我们对题目分析, 给出一个状态, 假设一个状态F(i):
F(i)表示给定字符串的的前i个字符能否根据字典中的词成功分离
接下来我们就可以把这个问题分解为:
给定字符串前1个字符( F(1) )是否可以被分离, 前2个字符( F(2) )是否可以被分离, 前3个字符…一直到前n个字符( F(n) )
“leetcode”, 为了判断这个字符串是否可以被分割, 我们首先要从头开始判断, 也就是F(1)( 给定字符串的前1个字符是否可以分割 ), 因此我们需要一个辅助变量 F(0) 并将其记为 true
这样我们就可以给出状态的递推
F(i): F(j) && j < i && substr(j, i-j) -----F(i)记为true, 否则记为false
也就是说, 在 j < i 中, 只要能够找到一个 F(j) 为 true, 并且 从 j + 1 位置开始到 i - j 之间的字符串可以在字典中找到, 这样 F(i) 就可以记为 true
看例子说明:
“leetcode”
辅助变量F(0)记为 true
前1个字符, 为 “l”—>不可以被分割------F(1)记为false
前2个字符, 为 “le”—>不可以被分割------F(2)记为false
前3个字符, 为 “lee”—>不可以被分割------F(3)记为false
前4个字符, 为 “leet”—>可以被分割------F(4)记为 true
此时
F(0) F(1) F(3) F(4)
true false false true
前5个字符, 为 “leetc”—>不可以被分割------此时还不能将F(5)记为false, 因为 F(4) 为 true, 也就是说此时还要判断的是 "c"能否在词典中找到, "c"并不在词典中, F(5)记为 false
前6个字符, 为 “leetco”—>不可以被分割------此时还不能将F(6)记为false, 同理因为 F(4) 为 true, 也就是说此时还要判断的是 "co"能否在词典中找到, "co"并不在词典中, F(6)记为 false
同理一直到前8个字符, “leetcode”—>不可分割-----接下来判断"code", 在词典中可以找到, F(8)为true
返回值:
最后返回F(n)即可
这样描述可能还是有些抽象, 换一种好理解的方式来说:
“leetcode”, 我们去判断这个字符串能否分割的时候, 肯定是从"l"开始
逐个往后, 这也就是上面辅助变量F(0)的作用, 使得每次循环都可以从"l"开始往后判断, 当发现"leet"在词典中找到了, 说明这个单词可以分割出来, 就把t位置也就是F(4)记为true, 方便下一次递推, 对应到我们的思维当中, 也就是说这个单词属于完整的一个个体, 后面再去判断剩余的字符串是否可以分割的时候, 从"c"开始逐个判断即可, 只是上面给出的状态变量是F(i)表示的是前i个字符是否可以被分割, 所以多判断了一步.
代码如下:
class Solution {
public:
bool wordBreak(string s, unordered_set<string> &dict) {
int len = s.size();
vector<bool> v(len + 1, false);
v[0] = true;
for (int i = 1; i <= len; ++i)
{
for (int j = i - 1; j >= 0; --j)
{
if (v[j] && j < i && dict.find(s.substr(j, i - j)) != dict.end())
{
v[i] = true;
}
}
}
return v[len];
}
};
附牛客链接leetcode