Find the longest word given a collection

前端 未结 9 1574
既然无缘
既然无缘 2021-01-30 14:03

It is a google interview question and I find most answers online using HashMap or similar data structure. I am trying to find a solution using Trie if possible. Anybody could gi

9条回答
  •  清酒与你
    2021-01-30 14:37

    First off, nice question. The interviewer wants to see how you tackle the problem. In those kinds of problems you are required to analyse the problem and carefully choose a data structure.

    In this case, two datastructures come into my mind: HashMaps and Tries. HashMaps are not a good fit, because you don't have a complete key you want to lookup (you can use an inverted index based on maps, but you said you already found those solutions). You only have the parts- that is where the Trie is the best fit.

    So the idea with tries is that you can ignore branches of characters that are not in your dictionary while traversing the tree.

    In your case, the tree looks like this (I left out the branching for non-branching paths):

    *
       a
         bacus
       d 
         deltoid
       g
         a
           gaff
         i
           giraffe
       m 
         microphone
       r 
         reef
       q 
         qar
    

    So at each level of this trie, we look at the children of the current node and check if the child's character is in our dictionary.

    If yes: We go deeper in that tree and remove the child's character from our dictionary

    This goes on until you hit a leaf (no children anymore), here you know that this word contains all characters in this dictionary. This is a possible candidate. Now we want to go back in the tree until we find another match that we can compare. If the newest found match is smaller, discard it, if longer this is our possible best match candidate now.

    Some day, the recusion will finish and you'll end up with the desired output.

    Note that this works if there is a single longest word, otherwise you would have to return a list of candidates (this is the unknown part of the interview where you are required to ask what the interviewer wants to see as a solution).

    So you have required the Java code, here it is with a simplistic Trie and the single longest word version:

    public class LongestWord {
    
      class TrieNode {
        char value;
        List children = new ArrayList<>();
        String word;
    
        public TrieNode() {
        }
    
        public TrieNode(char val) {
          this.value = val;
        }
    
        public void add(char[] array) {
          add(array, 0);
        }
    
        public void add(char[] array, int offset) {
          for (TrieNode child : children) {
            if (child.value == array[offset]) {
              child.add(array, offset + 1);
              return;
            }
          }
          TrieNode trieNode = new TrieNode(array[offset]);
          children.add(trieNode);
          if (offset < array.length - 1) {
            trieNode.add(array, offset + 1);
          } else {
            trieNode.word = new String(array);
          }
        }    
      }
    
      private TrieNode root = new TrieNode();
    
      public LongestWord() {
        List asList = Arrays.asList("abacus", "deltoid", "gaff", "giraffe",
            "microphone", "reef", "qar");
        for (String word : asList) {
          root.add(word.toCharArray());
        }
      }
    
      public String search(char[] cs) {
        return visit(root, cs);
      }
    
      public String visit(TrieNode n, char[] allowedCharacters) {
        String bestMatch = null;
        if (n.children.isEmpty()) {
          // base case, leaf of the trie, use as a candidate
          bestMatch = n.word;
        }
    
        for (TrieNode child : n.children) {
          if (contains(allowedCharacters, child.value)) {
            // remove this child's value and descent into the trie
            String result = visit(child, remove(allowedCharacters, child.value));
            // if the result wasn't null, check length and set
            if (bestMatch == null || result != null
                && bestMatch.length() < result.length()) {
              bestMatch = result;
            }
          }
        }
        // always return the best known match thus far
        return bestMatch;
      }
    
      private char[] remove(char[] allowedCharacters, char value) {
        char[] newDict = new char[allowedCharacters.length - 1];
        int index = 0;
        for (char x : allowedCharacters) {
          if (x != value) {
            newDict[index++] = x;
          } else {
            // we removed the first hit, now copy the rest
            break;
          }
        }
        System.arraycopy(allowedCharacters, index + 1, newDict, index,
            allowedCharacters.length - (index + 1));
    
        return newDict;
      }
    
      private boolean contains(char[] allowedCharacters, char value) {
        for (char x : allowedCharacters) {
          if (value == x) {
            return true;
          }
        }
        return false;
      }
    
      public static void main(String[] args) {
        LongestWord lw = new LongestWord();
        String longestWord = lw.search(new char[] { 'a', 'e', 'f', 'f', 'g', 'i',
            'r', 'q' });
        // yields giraffe
        System.out.println(longestWord);
      }
    
    }
    

    I also can only suggest reading the book Cracking the Coding Interview: 150 Programming Questions and Solutions, it guides you through the decision-making and construction those algorithms specialized on interview questions.

提交回复
热议问题