Implement Trie and find longest prefix string list

29293 ワード

  1 package leetcode;

  2 

  3 import java.util.ArrayList;

  4 import java.util.List;

  5 

  6 class TrieNode{

  7     Boolean isWord;//true if path till this node represent a string. 

  8     Integer freq;//numbers of strings share the same prefix

  9     Character nodeChar;//character for this node

 10     ArrayList<TrieNode> childNodes;

 11     public TrieNode(char c){

 12         childNodes = new ArrayList<TrieNode>();

 13         this.nodeChar = c;

 14         this.freq = 1;

 15         this.isWord = false;

 16     }

 17     public TrieNode(){

 18         childNodes = new ArrayList<TrieNode>();

 19         this.nodeChar = null;

 20         this.freq = 0;

 21         this.isWord = false;

 22     }

 23 }

 24 

 25 class Prefix{

 26     TrieNode root;

 27     String prefix;

 28     public Prefix(TrieNode root, String s){

 29         this.root = root;

 30         this.prefix = s;

 31     }

 32 }

 33 

 34 public class Trie {

 35     /*

 36     Trie is an efficient information retrieval data structure. 

 37     Using trie, search complexities can be brought to optimal limit (key length). 

 38     If we store keys in binary search tree, a well balanced BST will need time proportional to M * log N, 

 39     where M is maximum string length and N is number of keys in tree. 

 40     Using trie, we can search the key in O(M) time. 

 41     However the penalty is on trie storage requirements.

 42     */

 43     TrieNode root;

 44     public Trie(){

 45         root = new TrieNode();

 46     }

 47 

 48     public void insert(String s){

 49         if(s == null || s.length() == 0) return;

 50         TrieNode tmp = root;

 51         tmp.freq ++;// prefix freq ++

 52         for(int i = 0; i < s.length(); i ++){

 53             Boolean hasNode = false;

 54             for(int j = 0; j < tmp.childNodes.size(); j ++){

 55                 if(tmp.childNodes.get(j).nodeChar == s.charAt(i)){

 56                     tmp = tmp.childNodes.get(j);

 57                     tmp.freq ++;

 58                     hasNode = true;

 59                     break;

 60                 }

 61             }

 62             if(hasNode == false){

 63                 TrieNode newNode = new TrieNode(s.charAt(i));

 64                 tmp.childNodes.add(newNode);

 65                 tmp = newNode;

 66             }

 67         }

 68         tmp.isWord = true;

 69     }

 70 

 71     public Boolean searchString(String s){

 72         if(s == null || s.length() == 0) return false;

 73         TrieNode tmp = root;

 74         for(int i = 0; i < s.length(); i ++){

 75             Boolean containsChar = false;

 76             for(int j = 0; j < tmp.childNodes.size(); j ++){

 77                 if(tmp.childNodes.get(j).nodeChar == s.charAt(i)){

 78                     tmp = tmp.childNodes.get(j);

 79                     containsChar = true;

 80                     break;

 81                 }

 82             }

 83             if(containsChar == false){

 84                 return false;

 85             }

 86         }

 87         return tmp.isWord == true;

 88     }

 89 

 90     /*

 91      * During delete operation we delete the key in bottom up manner using recursion. The following are possible conditions when deleting key from trie,

 92      * 1. Key may not be there in trie. Delete operation should not modify trie.

 93      * 2. Key present as unique key (no part of key contains another key (prefix), nor the key itself is prefix of another key in trie). Delete all the nodes.

 94      * 3. Key is prefix key of another long key in trie. Unmark the leaf node.

 95      * 4. Key present in trie, having atleast one other key as prefix key. Delete nodes from end of key until first leaf node of longest prefix key.

 96     */

 97     public void delete(String s){

 98         if(searchString(s) == false) return;

 99         TrieNode tmp = root;

100         if(tmp.freq == 1){

101             tmp.childNodes.remove(0);

102             tmp.freq = 0;

103             return;

104         }

105         for(int i = 0; i < s.length(); i ++){

106             for(int j = 0; j < tmp.childNodes.size(); j ++){

107                 if(tmp.childNodes.get(j).nodeChar == s.charAt(i)){

108                     if(tmp.childNodes.get(j).freq == 1){

109                         tmp.childNodes.remove(j);

110                         tmp.freq --;

111                         return;

112                     }else{

113                         tmp.childNodes.get(j).freq --;

114                         tmp = tmp.childNodes.get(j);

115                     }

116                     break;

117                 }

118             }

119         }

120         tmp.isWord = false;

121 

122     }

123 

124     //find a list of string in the dictionary, which contains the longest prefix with the target string

125     public List<String> findAllStringWithSameLongestPrefix(String s){

126         Prefix tmp = findLongestPrefix(s);

127         List<String> result = new ArrayList<String>();

128         if(tmp.root.equals(root)) return result;

129         findAllStringInSubTree(tmp.root, new StringBuilder(tmp.prefix), result);

130         return result;

131     }

132 

133     private Prefix findLongestPrefix(String s){

134         TrieNode tmp = root;

135         StringBuilder sb = new StringBuilder();

136         for(int i = 0; i < s.length(); i ++){

137             Boolean containsChar = false;

138             for(int j = 0; j < tmp.childNodes.size(); j ++){

139                 if(tmp.childNodes.get(j).nodeChar == s.charAt(i)){

140                     sb.append(s.charAt(i));

141                     tmp = tmp.childNodes.get(j);

142                     containsChar = true;

143                     break;

144                 }

145             }

146             if(containsChar == false){

147                 return new Prefix(tmp, sb.toString());

148             }

149         }

150         return new Prefix(tmp, s);

151     }

152 

153     private void findAllStringInSubTree(TrieNode root, StringBuilder sb, List<String> result){

154         if(root.isWord == true){

155             result.add(sb.toString());

156         }

157         for(int i = 0; i < root.childNodes.size(); i ++){

158             TrieNode tmp = root.childNodes.get(i);

159             sb.append(tmp.nodeChar);

160             findAllStringInSubTree(tmp, new StringBuilder(sb), result);

161             sb.deleteCharAt(sb.length() - 1);

162         }

163     }

164     

165     public static void main(String[] args){

166         Trie trie = new Trie();

167         System.out.println("insert string into Trie:");

168         System.out.println("a, aq, ab, abb, aa, bbd, bd, ba, abc");

169         trie.insert("a");

170         trie.insert("aq");

171         trie.insert("ab");

172         trie.insert("abb");

173         trie.insert("aa");

174         trie.insert("bbd");

175         trie.insert("bd");

176         trie.insert("ba");

177         trie.insert("abc");

178         System.out.println("search string in Trie:");

179         System.out.println("abb: " + trie.searchString("abb"));

180         System.out.println("bd: " + trie.searchString("bd"));

181         System.out.println("bda: " + trie.searchString("bda"));

182         System.out.println("strings start with a:");

183         List<String> list1 = trie.findAllStringWithSameLongestPrefix("a");

184         for(int i = 0; i < list1.size(); i ++){

185             System.out.println(list1.get(i));

186         }

187         System.out.println("strings start with b:");

188         List<String> list2 = trie.findAllStringWithSameLongestPrefix("b");

189         for(int i = 0; list2 != null && i < list2.size(); i ++){

190             System.out.println(list2.get(i));

191         }

192         System.out.println("strings start with ab:");

193         List<String> list3 = trie.findAllStringWithSameLongestPrefix("ab");

194         for(int i = 0; i < list3.size(); i ++){

195             System.out.println(list3.get(i));

196         }

197         System.out.println("strings start with abcdef:");

198         List<String> list4 = trie.findAllStringWithSameLongestPrefix("abcdef");

199         for(int i = 0; list4 != null && i < list4.size(); i ++){

200             System.out.println(list4.get(i));

201         }

202         System.out.println("delete string from trie:");

203         trie.delete("ab");

204         System.out.println(trie.searchString("ab"));

205         System.out.println(trie.searchString("abb"));

206     }

207 }

Output:
insert string into Trie:

a, aq, ab, abb, aa, bbd, bd, ba, abc

search string in Trie:

abb: true

bd: true

bda: false

strings start with a:

a

aq

ab

abb

abc

aa

strings start with b:

bbd

bd

ba

strings start with ab:

ab

abb

abc

strings start with abcdef:

abc

delete string from trie:

false

true