前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Google 面试题分析 | 字典里面的最长单词

Google 面试题分析 | 字典里面的最长单词

作者头像
汤高
发布2018-01-11 15:00:55
8250
发布2018-01-11 15:00:55
举报
文章被收录于专栏:积累沉淀

描述

给定一个字符串列表words,找到words最长的word,使得这个word可用words中的其他word一次一个字符地构建。如果有多个可选答案,则返回最长的且具有最小字典序的word。

样例

Ⅰ. Input: words ="w","wo","wor","worl","world"

    Output: "world"

    Explanation: “world”可通过”w”, “wo”, “wor”, “worl”一次一个字符进行构建。

Ⅱ . Input: words ="a", "banana", "app", "appl","ap", "apply", "apple"

     Output:"apple"

    Explanation: “apply”和”apple”都可以由其他字符构建。但”apple”的字典序要小于”apply”。

注意:

所有的输入字符只包含小写字符。

    words的长度在1, 1000范围内。

    wordsi的长度在1, 30范围内。

解题思路

方法一:直接采用暴力搜索。

对于每一个word,检查是否其前缀都在words中。可以用words构建set。初始化ans=””,words,对每个元素,在set中寻找是否有其所有前缀。如果当前word合题,且长度大于ans,或长度等于ans但字典序小于ans,则修改ans为当前word。也可以先对words排序,按照长度从小到大,长度相同按照字典顺序。这样只要word合题就修改ans。

时间复杂度:O(sum(w_i^2)),w_i表示wordsi的长度。对于每一个word,通过哈希表检查是否所有的前缀都在set当中需要O(w_i^2)。

空间复杂度:O(sum(w_i))用于创建set。

方法二:因为涉及到了字符串的前缀,所以使用Trie结构(一种字符串前缀树)。

trie树的介绍参见 Trie树介绍

把每个word放入Trie中,对Trie进行DFS,只搜索终结节点。每个找到的节点中(除了根)从根到该节点路径代表该节点的word。之后同方法一:如果当前word合题,且长度大于ans,或长度等于ans但字典序小于ans,则修改ans为当前word。

时间复杂度:O(sum(w_i)),w_i是wordsi的长度。这是构建和便利Trie的复杂度。如果使用BFS而不是DFS,并且把每个节点的子节点进行排序,那么我们就不需要再去检查当前的word时候比ans要好,后访问的节点一定要好于先访问的节点,但复杂度不变。

空间复杂度:O(sum(w_i))用于构建Trie。

代码实现

代码语言:javascript
复制
package trie;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;


public class Solution {

    class Trie {
        //待构建的字符串列表
        private String words[];
        private Node root;
        
        public Trie(String[] words){
            this.root=new Node();
            this.words=words;
        }
        public Node builtTrie(){
            int index=0;
            for (int i=0;i<words.length;i++){
                insert(words[i],++index);
            }
            return root;
        }
        /**
         *@param index表示在words数组中的索引,方便在trie节点中快速获取该单词
         */
        public void insert(String word,int index){
            if(word==""||word==null){
                return;
            }
            Node cur=root;
            char [] chars=word.toCharArray();
            for(int i=0;i<chars.length;i++){
                //如果不存在该值,则创建新节点
                char val=chars[i];
                if(!cur.getChildrens().containsKey(val)){
                    Node newNode=new Node();
                    newNode.setVal(val);
                    cur.getChildrens().put(val, newNode);
                }
                //如果已经存在则pass
                cur=cur.getChildrens().get(val);
            }
            cur.setEnd(index);
            
        }
        
       public  String DFS(){
            String result="";
            Stack<Node> stack=new Stack<Node>();
            stack.push(root);
            while(!stack.isEmpty()){
                Node node=stack.pop();
                if(node.getEnd()>0||node==root){
                    if(node!=root){
                        String word= this.words[node.getEnd()-1];
                        if(word.length()>result.length()||
                                word.length()==result.length()&&result.compareTo(word)>0){//最长的且具有最小字典序的word
                            result=word;
                        }
                    }
                    for(Node n:node.getChildrens().values()){//拿到子节点
                        stack.push(n);
                    }
                }
            }
            return result;
            
        }
    }
       
    class Node {
        // 节点字符值
        private char val;
        // 节点的子节点,即以根节点到该节点的值组成的字符串为前缀的字符串构建的节点
        private Map<Character, Node> childrens = new HashMap<Character, Node>();
        // 是否为结束节点,即一个字符串是否到达末尾节点 当end>0时表示结束节点  该节点存储单词在words列表中的位置
        private int end = 0;
       
        public char getVal() {
            return val;
        }

        public void setVal(char val) {
            this.val = val;
        }

        public Map<Character, Node> getChildrens() {
            return childrens;
        }

        public void setChildrens(Map<Character, Node> childrens) {
            this.childrens = childrens;
        }

        public int getEnd() {
            return end;
        }

        public void setEnd(int end) {
            this.end = end;
        }
    }

   
   
    public static void main(String[] args) {
        String[] words=new String[]{"a", "banana", "app", "appl", "ap", "apply", "apple"};
        //String[] words=new String[]{"w","wo","wor","worl", "world"};
        Solution s=new Solution();
        Trie t=s.new Trie(words);
        t.builtTrie();
        System.out.println( t.DFS());  
         
     }
}

转载请指明出处https://cloud.tencent.com/developer/article/1018327

参考 https://mp.weixin.qq.com/s/WTXUt9C0YEl6171HbVWXWQ

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-01-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 描述
    • 样例
      • 解题思路
        • 代码实现
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档