648.单词替换
在英语中,我们有一个叫做 词根(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"
提示:
1 <= dictionary.length <= 1000
1 <= dictionary[i].length <= 100
dictionary[i] 仅由小写字母组成。
1 <= sentence.length <= 10^6
sentence 仅由小写字母和空格组成。
sentence 中单词的总量在范围 [1, 1000] 内。
sentence 中每个单词的长度在范围 [1, 1000] 内。
sentence 中单词之间由一个空格隔开。
sentence 没有前导或尾随空格。
方法一

当我看到题后,想到方法是对句子sentence内每一个单词与每一个dictorary内的词根进行匹配,如果单词的前缀可以匹配上这个词根就直接用这个词根替换掉这个单词,遍历一遍直至所有的词根都与这个单词(可能已被替换)匹配与替换

class Solution {
    public String replaceWords(List<String> dictionary, String sentence) {
        //用每一个词根对每一个单词进行匹配/替换
        for(int i=0;i<dictionary.length;i++){
            String str=dictionary.get(i);
            //当句子含有这个词根字符串时再匹配
            if(sentence.contains(str)){
                //分割
                String[] lists=sentence.split(" ");
                //匹配
                for(int j=0;j<lists.length;j++){
                    if(lists[j].startsWith(str))
                        //匹配成功直接替换
                        lists[j]=str;
                }
                //连起来
                String result="";
                for(String string:lists){
                    result=result.concat(" ").concat(string);
                }
                sentence=result.trim();//去除开头结尾可能有的空格
            }   
        }
        return sentence;
    }
}
方法二

看了题解,发现字典树确实很适合
字典树学习笔记:此处欠一个链接
以下代码是leetcode官方解法代码,我加了一些注释

class Solution {
    public String replaceWords(List<String> dictionary, String sentence) {
        Trie trie = new Trie();
        for (String word : dictionary) {
            Trie cur = trie;
            //建立字典树,将每一个前缀单词添加进去
            for (int i = 0; i < word.length(); i++) {
                char c = word.charAt(i);
                cur.children.putIfAbsent(c, new Trie());
                cur = cur.children.get(c);
            }
            //前缀结尾必须有#,以遍历字典树时判断是否有完全符合该路径的前缀单词
            cur.children.put('#', new Trie());
        }
        String[] words = sentence.split(" ");
        for (int i = 0; i < words.length; i++) {
            words[i] = findRoot(words[i], trie);
        }
        return String.join(" ", words);
    }
    //查找可以替换的前缀
    public String findRoot(String word, Trie trie) {
        //缓冲字符串,匹配到字母就添加进这个缓冲字符串中
        StringBuffer root = new StringBuffer();
        Trie cur = trie;
        for (int i = 0; i < word.length(); i++) {
            char c = word.charAt(i);//获取到单词的第i+1个字母
            //如果这个字典树节点的孩子含有#就说明,有一个以该字母为终点的前缀
            if (cur.children.containsKey('#')) {
                return root.toString();
            }
            //如果孩子中没有包含#,并且没有包含 单词的下一个字母,则没有匹配成功,返回原单词
            if (!cur.children.containsKey(c)) {
                return word;
            }
            //以上两种情况都不符合,即孩子中含有单词的下一个字母,添加到缓冲字符串中
            root.append(c);

            cur = cur.children.get(c);
        }
        return root.toString();
    }
}

//创建字典树节点类
class Trie {
    //每一个节点有一群孩子children,由不同的字母作为索引
    Map<Character, Trie> children;

    public Trie() {
        children = new HashMap<Character, Trie>();
    }
}

Share this content: