手摸手提桶跑路——LeetCode648.单词替换

127 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第23天,点击查看活动详情

题目描述

在英语中,我们有一个叫做 词根(root) 的概念,可以词根 后面 添加其他一些词组成另一个较长的单词——我们称这个词为 继承词(successor)。例如,词根 an,跟随着单词 other(其他),可以形成新的单词 another(另一个)。

现在,给定一个由许多词根组成的词典 dictionary 和一个用空格分隔单词形成的句子 sentence。你需要将句子中的所有继承词用词根替换掉。如果 继承词 有许多可以形成它的 词根,则用 最短 的词根替换它。

你需要输出替换之后的句子。

示例 1:

输入:dictionary = ["cat","bat","rat"], sentence = "the cattle was rattled by the battery"
输出:"the cat was rat by the bat"

示例 2:

输入:dictionary = ["a","b","c"], sentence = "aadsfasf absbs bbab cadsfafs"
输出:"a a b c"

解题思路——Set枚举

这题很直接的,我们先将 sentence 字符串通过 split 分割成一个个的单词数组。然后遍历这个单词数组,对于其中的每个单词,都去 dictionary 里找有没有和它公共前缀相同的最短的单词,如果有的话则返回这个词典中最短的公共前缀的单词,否则就返回原单词。

这里为了减少查询的时间,可以通过将 dictionary 中的所有词存入 Set 集合中,后续遍历单词数组时,分别去查找该单词的 前一个字符、前两个字符、前三个字符...前n个字符是否存在于该 Set 集合中。

题解

var replaceWords = function(dictionary, sentence) {
    const dictionarySet = new Set();
    for (const root of dictionary) {
        dictionarySet.add(root);
    }
    const words = sentence.split(" ");
    for (let i = 0; i < words.length; i++) {
        const word = words[i];
        for (let j = 0; j < word.length; j++) {
            if (dictionarySet.has(word.substring(0, 1 + j))) {
                words[i] = word.substring(0, 1 + j);
                break;
            }
        }
    }
    return words.join(' ');
};

Trie2.png

解题思路——前缀树(字典树、Trie树)

手摸手提桶跑路——LeetCode208.实现Trie(前缀树) 过来的同学应该都理解了什么是 Trie 树。

这里通过 Trie 树我们能够快速找到存在于 Trie 树中的所有单词,而 Set 枚举中需要不断的通过 substring 截取前缀去 Set 里找有没有对应的元素,这个效率就很低了。

那么用 Trie 树我们应该怎么去写呢?来看看步骤:

  1. 创建一个 Trie 树。
  2. 然后遍历 dictionary 将所有元素添加进 Trie 树。
  3. 分割 sentence 为数组并遍历,对每个元素去 Trie 树中查询 最短路径 的前缀,并对该单词进行替换,如果没有查找到对应前缀开头的单词,就返回原字符串。

题解

class Trie {
    constructor() {
        this.children = {};
        this.isEnd = false;
    }
}
var replaceWords = function(dictionary, sentence) {
    const trie = new Trie();
    for(let word of dictionary) {
        let temp = trie;
        for(let w of word) {
            if(temp.children[w] === void 0) {
                temp.children[w] = new Trie();
            }
            temp = temp.children[w];
        }
        temp.isEnd = true;
    }

    const arr = sentence.split(" ");
    return arr.map(word=>{
        return findRoot(word, trie);
    }).join(" ")
};

const findRoot = (word, trie) => {
    let res = '';
    for (let w of word) {
        if (trie.children[w] != void 0) {
            res += w;
            trie = trie.children[w];
            if (trie.isEnd) return res;
        } else {
            return word;
        }
    }
    return word;
}

Trie1.png