LeetCode 算法:恢复空格

193 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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) <= 1000
  • dictionary 中总字符数不超过 150000
  • 你可以认为 dictionarysentence 中只包含小写字母。

思路分析

方法一

  1. 首先将 dictionary 中的单词转成 Set 方便后面好判断;
  2. 然后我们定义一个 res 来存储 sentence 中 前i个字符中未识别字符的个数,来计算下初值,res[0] 一定为 0,前0个字符没有字符,所以也没有未识别的字符;
  3. 然后来对 sentence 进行遍历,然后可以得知 前i个字符 最少未识别的字符为 res[i-1]+1
  4. 然后从 i-1 进行递减遍历考虑是否为字典中的单词,若判断是否为字典中的单词,记录 res[i] 的值;
  5. 如此可以得到 res 的值,最后返回 res[sentence.length]

方法二

  1. 方法一中一直遍历的是 sentence,时间会比较长;
  2. 方法二重新换一种思路,在遍历时可以得到最少未识别的字符 res[i-1]+1,遍历 dictionary 然后寻找 sentence 前i项一个字母一个字母增加行程的单词是否跟字典匹配,然后如果存在时,则 res[i]Math.min(res[i], res[i-dictionary[j].length])
  3. 返回 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

END