词典中最长的单词-前缀树

词典中最长的单词Java-前缀树

链接:词典中最长的单词

描述:给出一个字符串数组 words 组成的一本英语词典。返回 words 中最长的一个单词,该单词是由 words 词典中其他单词逐步添加一个字母组成。

若其中有多个可行的答案,则返回答案中字典序最小的单词。若无答案,则返回空字符串。

示例 1:

输入:words = ["w","wo","wor","worl", "world"]
输出:"world"
解释: 单词"world"可由"w", "wo", "wor", 和 "worl"逐步添加一个字母组成。

示例 2:

输入:words = ["a", "banana", "app", "appl", "ap", "apply", "apple"]
输出:"apple"
解释:"apply" 和 "apple" 都能由词典中的单词组成。但是 "apple" 的字典序小于 "apply"

提示:

1. 1 <= words.length <= 1000
2. 1 <= words[i].length <= 30
3. 所有输入的字符串 words[i] 都只包含小写字母。

分析:根据描述可知,最长的单词是由字典中较短的单词一步步叠加来的,也就是说字典中一定存在最长单词的所有前缀

​ 前缀树这种组合数据结构由此而生,当然,不同的题可以有不同的构造方法,基本思路如下:

​ 1. 构造虚头节点
​ 2. 构建头节点的孩子节点,由所有输入的字符串 words[i] 都只包含小写字母可知,可以构造26个子节点,如:当传入的字符为a时,在children[0]处构造子节点,当传入字符为ab时,在前一步基础上在children[0]节点的children[1]处构造子节点。
3. 当传入的字符构造结束时,在结束的子节点上将结束标志赋予true
在这里插入图片描述
如上图所示,当传入字典words = ["a", "d", "en"],前缀树构造如上,创造前缀树时从虚头节点开始,自顶向下创建,判断某个单词是否在前缀树中出现也从虚头节点开始,自顶向下判断单词中每个字符是否在节点中出现,最后判断isEnd是否为True

回归本题,题意中返回 words 中最长的一个单词,该单词是由 words 词典中其他单词逐步添加一个字母组成。,包含两层含义:

1.从虚头节点到最长单词,中间必有一条通路
2.通路每一层每个节点的isEND必须为True

故在前缀树中可实现两种方法,一是添加子节点,构造前缀树,二是判断某个单词是否由其他单词逐步添加一个字母而成

前缀树代码:

public class TrieTree {

    private TrieTree[] children;
    private boolean isEnd;
    public TrieTree(){
            this.children = new TrieTree[26];
            this.isEnd = false;
    }

    public void insert(String word){
        TrieTree temp = this;   //得到虚头节点
        for(int i=0;i<word.length();i++){
            int pos = word.charAt(i)-'a';
            if( temp.children[pos]==null)  //如果此节点已存在,跳过构造
                temp.children[pos] = new TrieTree();  //实例化子节点
            temp = children[pos];    //指针移至子节点,继续构造后续节点
        }
        temp.isEnd = true;			//单词末尾,将结束标志置为True
    }

    public boolean searchRes(String word){
        TrieTree temp = this;					//得到虚头节点
        for(int i=0;i<word.length();i++){
            int pos = word.charAt(i)-'a';		//依次判断单词中每个字符所处的节点位置
            if(temp.children[pos]==null||!temp.children[pos].isEnd){  //当该位置上无结点时或该节点不是结束节点时,不满足上述两条含义所述的内容,说明该单词不是最长单词,直接pass掉
                return false;
            }
            temp = temp.children[pos];
        }
        return true;
    }
}

找出最长单词代码:

 public  static String longestWord(String[] words) {
        String ans = "";
        int len = 0;
        TrieTree begin = new TrieTree();
        for(String word:words){
            begin.insert(word);
        }
        for(String word:words){
            if(begin.searchRes(word)){        //当该单词满足上述两条含义基本内容时
                int wordLen = word.length();
                if(wordLen>len||(wordLen==len&&word.compareTo(ans)<0)){  // 判断该单词长度是否与目前最长单词长度长,如果True,将此单词记为最长单词,如果长度相同,将字典序小的记为最长单词
                    len = wordLen;
                    ans = word;
                }
            }
        }
        return ans;
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值