《leetCode》:Add and Search Word - Data structure design

来源:互联网 发布:软件规格需求说明书 编辑:程序博客网 时间:2024/04/28 11:00

题目

Design a data structure that supports the following two operations:

void addWord(word)
bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.

For example:

addWord("bad")addWord("dad")addWord("mad")search("pad") -> falsesearch("bad") -> truesearch(".ad") -> truesearch("b..") -> true

Note:

You may assume that all words are consist of lowercase letters a-z.

思路一:报超时

直接借用一个容器来添加和搜索匹配,实现代码如下:

    public class WordDictionary {        // Adds a word into the data structure.        List<String> words = new ArrayList<String> ();        public void addWord(String word) {            words.add(word);        }        // Returns if the word is in the data structure. A word could        // contain the dot character '.' to represent any one letter.        public boolean search(String word) {            for(String str:words){                if(str.matches(word)){                    return true;                }            }            return false;        }    }

思路二

根据题目的提示,使用trie结构。

修改trie结构中的searchWord方法即可。在实现Trie结构的searchWord方法中并没有考虑处理通配符的情况,而这里我们需要考虑。

考虑的思路为:如果此通配符是单词的最后一个字符,则只需要判断该节点下是否还存在节点的leaf属性为true的节点。如果此通配符不是单词的最后一个字符,则需要遍历该节点的所有子节点所代表的情况。

代码如下:

    public class WordDictionary {        // Adds a word into the data structure.        private Trie t = new Trie();        public void addWord(String word) {            t.insert(word);        }        // Returns if the word is in the data structure. A word could        // contain the dot character '.' to represent any one letter.        public boolean search(String word) {            //先将word最后的点点给去掉            return t.search(word);        }         class TrieNode {            // Initialize your data structure here.            public boolean leaf;//标识一个word到此结束            public Map<Character,TrieNode> childrens = new HashMap<Character,TrieNode>();            public TrieNode() {            }        }        class Trie {            private TrieNode root;            public Trie() {                root = new TrieNode();            }            // Inserts a word into the trie.            public void insert(String word) {                Map<Character,TrieNode> childrens = root.childrens;                for(int i=0;i<word.length();i++){                    Character ch =word.charAt(i);                    TrieNode t = null;                    if(childrens.containsKey(ch)){                        t = childrens.get(ch);                    }                    else{//此字符是一个新的分支                        t = new TrieNode();                        childrens.put(ch, t);                    }                    //继续寻找或插入第二个字符                    childrens = t.childrens;                    //设置单词的标识                    if(i==word.length()-1){                        t.leaf = true;                    }                }            }            // Returns if the word is in the trie.            public boolean search(String word) {                TrieNode t = searchWord(word,root);                return t!=null&&t.leaf;            }            public TrieNode searchWord(String word,TrieNode node){                Map<Character,TrieNode> childrens = node.childrens;                TrieNode t = null;                for(int i=0;i<word.length();i++){                    Character ch = word.charAt(i);                    if(ch=='.'){                        Set<Character>  set = childrens.keySet();                        TrieNode tt = null;                        //如果是最后一个通配符,则只要还存在分支节点的leaf为true,则就能匹配                        if(i==word.length()-1){                            for(Character c :set){                                tt = childrens.get(c);                                if(tt.leaf){                                    return tt;                                }                            }                            return null;                        }                        //对每个分支进行匹配检查                        for(Character c:set){                            t = childrens.get(c);                            tt =searchWord(word.substring(i+1),t);                            if(tt!=null){                                return tt;                            }                        }                        return null;//所有的都没有找到;                    }                    else if(ch!='.'&&!childrens.containsKey(ch)){//如果没有此分支,则返回null                        return null;                    }                    else{//如果有此分支,则更新childrens                        t = childrens.get(ch);                        childrens = t.childrens;                    }                }                return t;            }            // Returns if there is any word in the trie            // that starts with the given prefix.            public boolean startsWith(String prefix) {                TrieNode t = searchWord(prefix,root);                return t!=null;            }        }        // public static void main(String[] args){        //  WordDictionary wd = new WordDictionary();        //  wd.addWord("apple");        //  String str = "......";        //  System.out.println(wd.search(str));        // }    }    // Your WordDictionary object will be instantiated and called as such:    // WordDictionary wordDictionary = new WordDictionary();    // wordDictionary.addWord("word");    // wordDictionary.search("pattern");

很遗憾,此代码没有AC,只能通过11/13个case。

代码重新进行了分析,实在是不知道问题出现在哪。而leetcode提供的测试用例实在是过于庞大,不方便debug。

对以上的代码进行了重构,如下:

    public class WordDictionary {        // Adds a word into the data structure.        private TrieNode root = new TrieNode();        public void addWord(String word) {            Map<Character,TrieNode> childrens = root.childrens;            for(int i=0;i<word.length();i++){                Character ch =word.charAt(i);                TrieNode t = null;                if(childrens.containsKey(ch)){                    t = childrens.get(ch);                }                else{//此字符是一个新的分支                    t = new TrieNode();                    childrens.put(ch, t);                }                //继续寻找或插入第二个字符                childrens = t.childrens;                //设置单词的标识                if(i==word.length()-1){                    t.leaf = true;                }            }        }        // Returns if the word is in the data structure. A word could        // contain the dot character '.' to represent any one letter.        public boolean search(String word) {                return searchWord(word,root);        }         private boolean searchWord(String word,TrieNode node) {             if(word==null||node ==null){                 return false;             }             if(word.length()==0){                 return node.leaf;             }             Map<Character,TrieNode> childrens = node.childrens;             Character ch =word.charAt(0);             if(ch=='.'){                 for(Character c:childrens.keySet()){                     if(searchWord(word.substring(1),childrens.get(c))){                         return true;                     }                 }             }             else if(ch!='.'&&!childrens.containsKey(ch)){                 return false;             }             else{                 return  searchWord(word.substring(1),childrens.get(ch));             }             return false;        }    }    class TrieNode {        // Initialize your data structure here.        public boolean leaf;//标识一个word到此结束        public Map<Character,TrieNode> childrens = new HashMap<Character,TrieNode>();        public TrieNode() {        }    }

居然报超时。

继续将类似于如下的代码借用中间变量提取出来,以避免求取多次。

            if(ch=='.'){                 for(Character c:childrens.keySet()){                     if(searchWord(word.substring(1),childrens.get(c))){                         return true;                     }                 }             }

完整代码如下:

    public class WordDictionary {        // Adds a word into the data structure.        private TrieNode root = new TrieNode();        public void addWord(String word) {            Map<Character,TrieNode> childrens = root.childrens;            for(int i=0;i<word.length();i++){                Character ch =word.charAt(i);                TrieNode t = null;                if(childrens.containsKey(ch)){                    t = childrens.get(ch);                }                else{//此字符是一个新的分支                    t = new TrieNode();                    childrens.put(ch, t);                }                //继续寻找或插入第二个字符                childrens = t.childrens;                //设置单词的标识                if(i==word.length()-1){                    t.leaf = true;                }            }        }        // Returns if the word is in the data structure. A word could        // contain the dot character '.' to represent any one letter.        public boolean search(String word) {                return searchWord(word,root);        }         public boolean searchWord(String word,TrieNode node) {             if(word==null||node ==null){                 return false;             }             if(word.length()==0){                 return node.leaf;             }             Map<Character,TrieNode> childrens = node.childrens;             Character ch =word.charAt(0);             if(ch=='.'){                 Set<Character> set = childrens.keySet();                 String str = word.substring(1);                 for(Character c:set){                     if(searchWord(str,childrens.get(c))){                         return true;                     }                 }             }             else if(!childrens.containsKey(ch)){                 return false;             }             else {                 return  searchWord(word.substring(1),childrens.get(ch));             }             return false;        }    }    class TrieNode {        // Initialize your data structure here.        public boolean leaf;//标识一个word到此结束        public Map<Character,TrieNode> childrens = new HashMap<Character,TrieNode>();        public TrieNode() {        }    }

这样就AC 了,这个题真心不容易。

0 0
原创粉丝点击