【问题标题】:Autocomplete using Tries使用 Tries 自动完成
【发布时间】:2014-05-07 06:27:32
【问题描述】:
import java.util.ArrayList;


public class AutoComplete {
    boolean newWord = false;
    ArrayList<String> all = new ArrayList<String>();

    static TrieNode root = new TrieNode('!', false, null);

    void add(String s){
        TrieNode temp = root;
//      TrieNode parent = root;

        for(int i=0; i < s.length(); i++){
            int t = s.charAt(i);
            t = t - 97;
            while((temp.links[t]) != null && i < s.length()-1){

                temp = temp.links[t];
                t = s.charAt(++i);
                t = t - 97;

//              parent = temp;
            }
            if( i != s.length()-1){
                temp.links[t] = new TrieNode((char)(97+t), false, null);
//              parent = temp.links[t];
            }
            else{
                temp.links[t] = new TrieNode((char) (97+t), true, null);
//              parent = temp.links[t];         
            }
            temp = temp.links[t];
        }
    }

    void readTree(String find){
        int len = find.length();
        int i = 0;
        TrieNode temp = root;
        String match = "";
        while(i != len){
            int t = find.charAt(i);
            t = t - 97;
            temp = temp.links[t];
            if(temp == null)
                break;
            match = match + temp.letter;
            i++;
        }
        if(match.length() > 0)
            match = match.substring(0,match.length()-1);
        printAll(temp, match);
    }

    void printAll(TrieNode t, String parent){
        if(t== null)
            return;
        parent = parent + t.letter;
        if(t.fullWord){
            System.out.println(parent);
        }
        for(int i = 0; i < 26; i++){
            printAll(t.links[i], parent);
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        AutoComplete a = new AutoComplete();

        a.add("tea");
        a.add("team");
        a.add("teach");
        a.add("teacher");
        a.readTree("t");
    }

}

我正在尝试使用 Trie 实现自动完成,当 Trie 中的元素从较低长度添加到较高长度时,它可以正常工作

如果我按此顺序添加元素

a.add("tea");
a.add("team");
a.add("teach");
a.add("teacher");

我得到a.readTree("t");的以下输出

tea
teach
teacher
team

但是如果我按这个顺序添加元素

a.add("teacher");
a.add("teach");
a.add("team");
a.add("tea");

我得到a.readTree("t");的以下输出

tea

最终工作解决方案

public class AutoComplete {
    void add(String s, TrieNode root){
        //To keep the root node intact
        TrieNode temp = root;

        //Iterate through each char in string s
        for(int i=0; i < s.length(); i++){
            //each character in string
            int t = s.charAt(i);
            //its corresponding value in array links 
            t = t - 'a';
            //if some part of string is already present in array then just loop through it except th
            while((temp.links[t]) != null && i < s.length()-1){
                //increment i since first char is present
                i = i +1;
                //increment in trie
                temp = temp.links[t];
                //go to next char in string and 
                //go to that char location in array
                t = s.charAt(i)- 'a';
            }
            //Add only till before the last character
            if( i < s.length()-1){
                temp.links[t] = new TrieNode((char)('a'+t), false);
            }
            //for last character of string
            else{
                // if last character is not present
                if(temp.links[t] == null){
                    temp.links[t] = new TrieNode((char) ('a'+t), true);                 
                }
                // if last character already exist
                else{
                    temp.links[t].fullWord = true;
                }
            }
            //increment the trie
            temp = temp.links[t];
        }
    }
    void readTree(String find, TrieNode root){
        //get length in len
        int len = find.length();
        int i = 0;
        TrieNode temp = root;
        //initialize string to store the result
        String match = "";
        while(i < len){
            //get first char of search string
            int t = find.charAt(i) - 'a';
            //go to its array location
            temp = temp.links[t];
            //location is null then break else continue
            if(temp == null)
                break;
            //keep appending the found char and increment the index
            match = match + temp.letter;
            i++;
        }
        //if suggestions exist
        if(match.length() > 0)
            //pass the match string except for the last element
            match = match.substring(0,match.length()-1);
        printAll(temp, match);
    }

    void printAll(TrieNode t, String parent){
        if(t== null)
            return;
        parent = parent + t.letter;
        if(t.fullWord){
            System.out.println(parent);
        }
        for(int i = 0; i < 26; i++){
            printAll(t.links[i], parent);
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TrieNode root = new TrieNode('!', false);
        AutoComplete a = new AutoComplete();

        a.add("tea", root);
        a.add("team", root);
        a.add("teach", root);
        a.add("teacher", root);
        a.readTree("t", root);
    }

}

【问题讨论】:

  • 那么,您的具体问题是什么?代码的哪一部分没有按照您的预期运行 - 您希望该代码执行什么操作?这更像是一个错误报告而不是一个问题,所以它是 stackoverflow 的 OT。
  • 随机注释 - 修改循环内部的 for 循环变量通常会导致代码相当不可读,难以遵循 - 最好完全摆脱 while 循环。你可以说int t = s.charAt(i) - 97; - 没有必要把它分成两行。并且请使用'a' 而不是97,因为大多数人不会记住字符代码。

标签: java data-structures autocomplete trie


【解决方案1】:

问题出在这里:

else{ //i == s.length - 1
        temp.links[t] = new TrieNode((char) (97+t), true, null);      
    }

当你添加“teach”时,它会在 char 'h' 处新建一个节点,替换教师的节点 'h'。 你应该这样写:

else{ //i == s.length - 1
        if(temp.links[t] == null) {
            temp.links[t] = new TrieNode((char) (97+t), true, null);    
        } 
        else {
            // change the leaf tag from false to true 
        }
    }

【讨论】:

    【解决方案2】:

    Trie 的概念在您的代码中似乎没有得到很好的体现。很难辨别forwhile 循环的所有可能情况并且仍然可读。在“让它运行,让它正确,让它快速”的方式中,你应该让你的第一个实现尽可能简单。

    鉴于将字符串添加到您的Trie 的顺序确实会影响您的查询结果,您的代码显然还没有运行。为了使其尽可能简单,您只需要查看新添加的字符串的第一个字符,并根据您是否在root 中找到它并在之后使用递归。这可能会破坏您的运行时,但这只是您的第三个问题(在使其正确之后)。如果您不向我们展示您希望如何实施TrieNode,则需要进行太多更改。

    【讨论】:

      猜你喜欢
      • 2014-05-31
      • 1970-01-01
      • 2016-02-27
      • 2014-12-12
      • 2011-06-28
      • 2017-08-14
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多