Data structures 谷歌搜索建议的实现

Data structures 谷歌搜索建议的实现,data-structures,Data Structures,在最近的一次亚马逊采访中,我被要求实现谷歌的“建议”功能。当用户输入“Aeniffer Aninston”时,谷歌建议“你是说Jenifer Aninston吗?”。我试图用散列法来解决这个问题,但无法覆盖角落的情况。请告诉我您对此的想法。有4种最常见的错误类型- 省略字母:“stck”而不是“stack” 一个字母打字错误:“styck”而不是“stack” 额外字母:“斯塔克”而不是“斯塔克” 相邻字母交换:“satck”而不是“stack” 顺便说一句,我们可以交换的不是相邻的字母,而是任

在最近的一次亚马逊采访中,我被要求实现谷歌的“建议”功能。当用户输入“Aeniffer Aninston”时,谷歌建议“你是说Jenifer Aninston吗?”。我试图用散列法来解决这个问题,但无法覆盖角落的情况。请告诉我您对此的想法。

有4种最常见的错误类型-

  • 省略字母:“stck”而不是“stack”
  • 一个字母打字错误:“styck”而不是“stack”
  • 额外字母:“斯塔克”而不是“斯塔克”
  • 相邻字母交换:“satck”而不是“stack”
  • 顺便说一句,我们可以交换的不是相邻的字母,而是任何字母,但这不是常见的打字错误

    初始状态类型的单词。从初始顶点运行BFS/DFS。搜索深度是您自己的选择。请记住,搜索深度的增加会导致“可能更正”的数量急剧增加。我认为深度4-5是一个好的开始

    生成“可能的更正”后,在字典中搜索每个生成的候选词-在已排序字典中进行二进制搜索,或在已填充字典的trie中进行搜索

    Trie速度更快,但二进制搜索允许在随机访问文件中搜索,而无需将字典加载到RAM。您只需加载预计算的
    integer
    array[]
    Array[i]
    提供访问第i个字时要跳过的字节数。随机访问文件中的单词应按排序顺序写入。如果您有足够的内存来存储字典,请使用trie

    建议更正前,检查键入的单词-如果它在字典中,则不提供任何内容。

    更新

    生成更正应该由BFS完成-当我尝试DFS时,“Jeniffer”之类的条目显示“编辑距离=3”。DFS不起作用,因为它可以在一个步骤中进行大量更改—例如,
    Jniffer->nJiffer->enJiffer->eJniffer->Jeniffer
    ,而不是
    Jniffer->Jeniffer

    BFS生成更正的示例代码

    static class Pair
        {
            private String word;
            private byte dist; 
            // dist is byte because dist<=128.
            // Moreover, dist<=6 in real application
    
            public Pair(String word,byte dist)
            {
                this.word = word;
                this.dist = dist;
            }
    
            public String getWord()
            {
                return word;
            }
    
            public int getDist()
            {
                return dist;
            }
        }
    
    
        public static void main(String[] args) throws Exception
        {
    
            HashSet<String> usedWords;
            HashSet<String> dict;
            ArrayList<String> corrections;
            ArrayDeque<Pair> states;
    
            usedWords = new HashSet<String>();
            corrections = new ArrayList<String>();
            dict = new HashSet<String>();
            states = new ArrayDeque<Pair>();
    
            // populate dictionary. In real usage should be populated from prepared file.
            dict.add("Jeniffer");
            dict.add("Jeniffert"); //depth 2 test
    
            usedWords.add("Jniffer");
            states.add(new Pair("Jniffer", (byte)0));
            while(!states.isEmpty())
            {
                Pair head = states.pollFirst();
                //System.out.println(head.getWord()+" "+head.getDist());
                if(head.getDist()<=2) 
                {
                    // checking reached  depth.
                    //4 is the first depth where we don't generate anything  
    
                    // swap adjacent letters
                    for(int i=0;i<head.getWord().length()-1;i++)
                    {
                        // swap i-th and i+1-th letters
                        String newWord = head.getWord().substring(0,i)+head.getWord().charAt(i+1)+head.getWord().charAt(i)+head.getWord().substring(i+2);
                        // even if i==curWord.length()-2 and then i+2==curWord.length 
                        //substring(i+2)  doesn't throw exception and returns empty string
                        // the same for substring(0,i) when i==0
    
                        if(!usedWords.contains(newWord))
                        {
                            usedWords.add(newWord);
                            if(dict.contains(newWord))
                            {
                                corrections.add(newWord);
                            }
                            states.addLast(new Pair(newWord, (byte)(head.getDist()+1)));
                        }
                    }
    
                     // insert letters 
                    for(int i=0;i<=head.getWord().length();i++)
                          for(char ch='a';ch<='z';ch++)
                          {
                                String newWord = head.getWord().substring(0,i)+ch+head.getWord().substring(i);
                                if(!usedWords.contains(newWord))
                                {
                                    usedWords.add(newWord);
                                    if(dict.contains(newWord))
                                    {
                                        corrections.add(newWord);
                                    }
                                    states.addLast(new Pair(newWord, (byte)(head.getDist()+1)));
                                }
                          }
                }
            }
    
            for(String correction:corrections)
            {
              System.out.println("Did you mean "+correction+"?");
            }
    
            usedWords.clear();
            corrections.clear();
            // helper data structures must be cleared after each generateCorrections call - must be empty for the future usage. 
    
        }
    
    静态类对
    {
    私有字符串字;
    专用字节距离;
    
    //dist是byte,因为dist谢谢你的解释。但是我不理解“生成可能的更正”部分。我想你说的是所有可能的组合。例如,如果有人键入“Jniffer Aninston”,可能的更正是什么,以及它将如何映射到原始单词“Jeniffer Aninston”