Tries Data Structure
Implement Tries with Array
1. insert - insert a string if the string doesn't exist, nop otherwise
2. contains - check if input String exists in the Tries
3. autocomplete - return all words which contain input String as suffix




public  void add(TNode r, int[] arr, int k) {
        if( k < arr.length) {
            if(r.array[arr[k]] == null)
                r.array[arr[k]] = new TNode();

            add(r.array[arr[k]], arr, k+1);
        }else if(k == arr.length){
            r.isWord = true;
        }
    }

    public  boolean contains(TNode r, int[] arr, int h) {
        if(r != null){
            if(h < arr.length) {
                return contains(r.array[arr[h]], arr, h+1);
            }else if (h == arr.length){
                return r.isWord;
            }
        }
        return false;
    }
    public  void addWord(TNode r,  String word, int k) {
        if( k < word.length()) {
            if(r.array[map(word.charAt(k))] == null)
                r.array[map(word.charAt(k))] = new TNode();

            addWord(r.array[map(word.charAt(k))], word, k+1);
        }else{
            r.isWord = true;
        }
    }
    public  boolean containsWord(TNode r, String word, int k) {
          if(r != null){
              if(k == word.length())
                  return r.isWord;
              else if(k < word.length()){
                  return containsWord(r.array[map(word.charAt(k))], word, k+1);
              }
          }
          return false;
    }

Implement Tries with HashMap
1. insert
2. contains
3. autocomplete

/**
    * insert str to Tries from the root, if str doesn't exist in Tries
    * set isWord to be true, and assign str to word
    * if str does exist in the tries, do nothing
    *
    * @param root   the root node of Tries, it can't be null
    * @param str    the String is being inserted
    * @param index  index of str, initial value is zero
    *
    * return void
    */
    public static void insert(XNode root, String str, int index) {
        if(index == str.length()) {
            root.isWord = true;
            root.word = str;
        } else {
            char ch = str.charAt(index);
            XNode node = root.map.get(ch);
            if(node == null) {
                node = new XNode(false);
                root.map.put(ch, node);
            }
            insert(node, str, index+1);
        }
    }

    /**
    * check if the str exist in the Tries,
    *
    * @param root the root of Tries
    * @param str  the String to be checked
    * @param index index of str
    *
    * @return true if str exists in the Tries, false otherwise
    */
    public static boolean contains(XNode root, String str, int index) {
        if(index == str.length()) {
            return root.isWord;
        } else {
            if(root.map.containsKey(str.charAt(index))) {
                return contains(root.map.get(str.charAt(index)), str, index + 1);
            } else {
                return false;
            }
        }
    }

    public static XNode autocomplete(XNode root, String partialWord, int index) {
        if(index == partialWord.length()) {
            return root;
        }else {
            XNode node = root.map.get(partialWord.charAt(index));
            if(node != null) {
                return autocomplete(node, partialWord, index + 1);
            }
            return null;
        }
    }
    public static void autocompleteList(XNode node, String partialWord, int index, List<String> list) {
        if(node.isWord)
            list.add(node.word);
        else{
            for(Map.Entry<Character, XNode> entry : node.map.entrySet()){
                if(entry.getValue().isWord)
                    list.add(entry.getValue().word);
                else
                    autocompleteList(entry.getValue(), partialWord, index+1, list);
            } 
        }
    }