持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情
给定一个字符串 s 和一个字符串字典 wordDict ,在字符串 s 中增加空格来构建一个句子,使得句子中所有的单词都在词典中。以任意顺序 返回所有这些可能的句子。
注意: 词典中的同一个单词可能在分段中被重复使用多次。
示例 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 <= s.length <= 201 <= wordDict.length <= 10001 <= wordDict[i].length <= 10s和wordDict[i]仅有小写英文字母组成wordDict中所有字符串都 不同
思路
本题可以用动态规划求解。定义n为字符串s的长度,fn(i)为字符串s[i...n-1]可拆分的单词组,遍历字典,如果s[i...j](i <= j <= n-1)在字典中,fn(i) = s[i...j] + fn(j+1)。初始状态fn(n) = []。为了优化在字典中查找匹配的字符串,需要做一些预处理,我们先把字典排序,再定义一个map,用字典中字符串首字母作为key,存储以key开头的字符串的开始下标和结束下标,查找时,先用s[i]在map中查找开始和结束下标,缩小查找范围。
解题
/**
* @param {string} s
* @param {string[]} wordDict
* @return {string[]}
*/
var wordBreak = function (s, wordDict) {
wordDict.sort();
const n = wordDict.length;
const map = new Map();
let prev = "";
let item = [];
for (let i = 0; i < wordDict.length; i++) {
let first = wordDict[i][0];
if (first !== prev) {
item[1] = i;
prev = first;
item = [i, n];
map.set(first, item);
}
}
const res = [];
const fn = (i, words) => {
if (i >= s.length) {
res.push(words.join(' '))
return
}
let char = s[i];
if (map.has(char)) {
const [start, end] = map.get(char);
const subStr = s.slice(i);
for (let j = start; j < end; j++) {
if (subStr.startsWith(wordDict[j])) {
words.push(wordDict[j]);
fn(i + wordDict[j].length, words);
words.pop();
}
}
}
};
fn(0, [])
return res
};