携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 27 天,点击查看活动详情。
恢复空格
原题地址
哦,不!你不小心把一个长篇文章中的空格、标点都删掉了,并且大写也弄成了小写。像句子 "I reset the computer. It still didn’t boot!" 已经变成了 "iresetthecomputeritstilldidntboot"。在处理标点符号和大小写之前,你得先把它断成词语。当然了,你有一本厚厚的词典 dictionary,不过,有些词没在词典里。假设文章用 sentence 表示,设计一个算法,把文章断开,要求未识别的字符最少,返回未识别的字符数。
注意: 本题相对原题稍作改动,只需返回未识别的字符数
示例:
输入:
dictionary = ["looked","just","like","her","brother"]
sentence = "jesslookedjustliketimherbrother"
输出: 7
解释: 断句后为"jess looked just like tim her brother",共7个未识别字符。
提示:
0 <= len(sentence) <= 1000dictionary中总字符数不超过150000。- 你可以认为
dictionary和sentence中只包含小写字母。
思路分析
方法一
- 首先将
dictionary中的单词转成Set方便后面好判断; - 然后我们定义一个
res来存储sentence中 前i个字符中未识别字符的个数,来计算下初值,res[0]一定为0,前0个字符没有字符,所以也没有未识别的字符; - 然后来对
sentence进行遍历,然后可以得知 前i个字符 最少未识别的字符为res[i-1]+1; - 然后从
i-1进行递减遍历考虑是否为字典中的单词,若判断是否为字典中的单词,记录res[i]的值; - 如此可以得到
res的值,最后返回res[sentence.length]。
方法二
- 方法一中一直遍历的是
sentence,时间会比较长; - 方法二重新换一种思路,在遍历时可以得到最少未识别的字符
res[i-1]+1,遍历dictionary然后寻找sentence前i项一个字母一个字母增加行程的单词是否跟字典匹配,然后如果存在时,则res[i]为Math.min(res[i], res[i-dictionary[j].length]); - 返回
res[sentence.length]。
AC 代码
方法一
/**
* @param {string[]} dictionary
* @param {string} sentence
* @return {number}
*/
var respace = function(dictionary, sentence) {
const len = sentence.length
const res = new Array(len + 1)
const wordDict = new Set()
for (const word of dictionary) {
wordDict.add(word)
}
res[0] = 0 // 前0个字符 没有字符 更没有未识别的字符
for (let i = 1; i <= len; i++) {
res[i] = res[i - 1] + 1 // 前i个字符的最少未识别的字符 保底的情况(可能还可以更少)
for (let j = i - 1; j >= 0; j--) { // j 从 i-1开始 word的长度从0开始
const word = sentence.substring(j, i)
if (wordDict.has(word)) {
res[i] = Math.min(res[i], res[j])
} else {
res[i] = Math.min(res[i], res[j] + i - j)
}
}
}
return res[len]
};
结果:
- 执行结果: 通过
- 执行用时:1008 ms, 在所有 JavaScript 提交中击败了9.76%的用户
- 内存消耗:48.7 MB, 在所有 JavaScript 提交中击败了24.39%的用户
- 通过测试用例:71 / 71
方法二
/**
* @param {string[]} dictionary
* @param {string} sentence
* @return {number}
*/
var respace = function(dictionary, sentence) {
const len = sentence.length
if(len === 0) return 0
let res = new Array(len).fill(0)
for(let i = 1; i <= len; i++){
res[i] = res[i - 1] + 1
// 上面表示,如果没有匹配那么dp[i]相比于dp[i-1]直接多1
// 接着讨论如果新加一个字符,组成了一个词的情况
for(let j = 0; j < dictionary.length; j++){
let word = dictionary[j].length
if(dictionary[j] === sentence.substring(i - word, i) && word <= i){
res[i] = Math.min(res[i], res[i - word])
}
}
}
return res[len]
};
结果:
- 执行结果: 通过
- 执行用时:124 ms, 在所有 JavaScript 提交中击败了80.49%的用户
- 内存消耗:48.6 MB, 在所有 JavaScript 提交中击败了26.83%的用户
- 通过测试用例:71 / 71