题目描述
原题链接:139. 单词拆分
解题思路
核心思路是采用Hash表的方式,存储wordDict
。每次采取切分一段字符串,然后在Hash表中匹配,看是否可在表中匹配到对应字符串。
(1)回溯法
class Solution {
private:
bool backtracking (const string& s, const unordered_set<string>& wordSet, int startIndex) {
if (startIndex >= s.size()) {
return true;
}
for (int i = startIndex; i < s.size(); i++) {
string word = s.substr(startIndex, i - startIndex + 1);
if (wordSet.find(word) != wordSet.end() && backtracking(s, wordSet, i + 1)) {
return true;
}
}
return false;
}
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
return backtracking(s, wordSet, 0);
}
};
此方式会超时。
(2)动态规划
- 动态规划五步曲:
(1)dp[j]数组含义: dp[j] == true
时,s中从0 ~ j - 1可以由wordDict
所组成。背包为字符串s,物品为字典单词。
(2)递推公式: 当在s中下标为[i-1, j]时,有对应的单词在wordDict中并且前i-1个字符可被wordDcit组成时, 让dp[j] = true。
(3)dp数组初始化: 为了便于计算让dp[j] = true。
(4)遍历顺序: 因为需要考虑顺序问题,例如appleandapple
,设apple
为1,and
为2,则应该得到为121才合法,如果得到的为112应不合法,不为我们的把目标。因此,这是一个考虑顺序的排列问题,应该先背包再物品。
(5)举例:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int m = s.size();
unordered_set<string> record(wordDict.begin(), wordDict.end());
vector<bool> dp(m, false);
dp[0] = true;
for(int j = 1; j <= m; j++) { // 先遍历背包
for(int i = 1; i <= j; i++) { // 再遍历物品
string str = s.substr(i - 1, j - i + 1); // 从i-1处开始截取,截取字符串长为j-i+1的字符
// 查找str是否在单词表中,同时也要求str之前的字符串也可由单词表组成
if(record.find(str) != record.end() && dp[i - 1] == true) {
dp[j] = true;
}
}
}
return dp[m];
}
};
参考文章:139. 单词拆分