题目
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
分隔时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。
示例 1:
输入:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
输出:
[
"cats and dog",
"cat sand dog"
]
示例 2:
输入:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
输出:
[
"pine apple pen apple",
"pineapple pen apple",
"pine applepen apple"
]
解释: 注意你可以重复使用字典中的单词。
示例 3:
输入:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
输出:
[]
动态规划四步走
1. 定义状态
2. 初始状态
3. 状态转移方程
4. 从dp[]中获取结果
具体到题目
定义状态
定义数组dp[i]表示前i个字符由wordDict组成的所有可能
初始状态
dp[0] = [];
状态转移方程
dp[i]需要遍历wordDict数组,遍历wordDict的每一个字符串str,令p=str.length,当str和s的前i个字符组成的子字符串的末尾相同时,则该dp[i] = dp[i-p]的每个元素加上str。
从dp[]中获取结果
dp[]的最后一项就是最终结果
完整代码
var wordBreak = function (s, wordDict) {
const len = s.length;
const dp = new Array(len + 1).fill(0).map(() => new Array());
dp[0] = [];
for (let i = 1; i < len + 1; i++) {
const filterList = wordDict.filter((item) => item.length <= i);
for (let j = 0; j < filterList.length; j++) {
const p = filterList[j].length;
const str = s.substring(i - p, i);
console.log(str, wordDict[j]);
if (str === filterList[j] && Array.isArray(dp[i - p])) {
if (i - p === 0) {
dp[i].push(str);
} else {
dp[i - p].forEach((item) => {
dp[i].push(`${item} ${str}`);
});
}
}
}
}
console.log(dp);
return dp.pop();
};
跑完用例发现当输入
const s =
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
const wordDict = [
'a',
'aa',
'aaa',
'aaaa',
'aaaaa',
'aaaaaa',
'aaaaaaa',
'aaaaaaaa',
'aaaaaaaaa',
'aaaaaaaaaa'
];
超时了,分析得出这种情况属于不能由wordDict,可以直接返回[],因此需要结合139题的代码一起判断,得到最终的代码如下
// @lc code=start
/**
* @param {string} s
* @param {string[]} wordDict
* @return {string[]}
*/
var wordBreak = function (s, wordDict) {
if (!canWordBreak(s, wordDict)) {
return [];
}
const len = s.length;
const dp = new Array(len + 1).fill(0).map(() => new Array());
dp[0] = [];
for (let i = 1; i < len + 1; i++) {
const filterList = wordDict.filter((item) => item.length <= i);
for (let j = 0; j < filterList.length; j++) {
const p = filterList[j].length;
const str = s.substring(i - p, i);
console.log(str, wordDict[j]);
if (str === filterList[j] && Array.isArray(dp[i - p])) {
if (i - p === 0) {
dp[i].push(str);
} else {
dp[i - p].forEach((item) => {
dp[i].push(`${item} ${str}`);
});
}
}
}
}
console.log(dp);
return dp.pop();
};
var canWordBreak = function (s, wordDict) {
const len = s.length;
const dp = new Array(len).fill(false);
const backtrack = (string, index) => {
if (index === string.length) {
return true;
}
if (dp[index]) {
return false;
}
for (let i = 0; i < wordDict.length; i++) {
const helpStr = string.substring(index);
if (helpStr.startsWith(wordDict[i])) {
const match = wordDict[i];
const matchLen = match.length;
if (backtrack(s, index + matchLen)) {
return true;
}
}
}
dp[index] = true;
return false;
};
const res = backtrack(s, 0);
console.log(res);
return res;
};