Skip to content

Commit 2ce2c73

Browse files
much improved solution by using Trie
1 parent 676ef2f commit 2ce2c73

File tree

1 file changed

+211
-0
lines changed

1 file changed

+211
-0
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
package package1;
2+
3+
import java.io.BufferedReader;
4+
import java.io.BufferedWriter;
5+
import java.io.File;
6+
import java.io.FileReader;
7+
import java.io.FileWriter;
8+
import java.io.IOException;
9+
import java.util.ArrayList;
10+
import java.util.Collections;
11+
import java.util.Comparator;
12+
import java.util.HashSet;
13+
import java.util.List;
14+
import java.util.Set;
15+
16+
public class ConcatenatedWordsII {
17+
18+
public static void main(String...args){
19+
try {
20+
String FILE_PATH = "/Users/SteveSun/Google Drive/Developer/wordsforproblem.txt";
21+
// String FILE_PATH = "/Users/SteveSun/Google Drive/Developer/first30.txt";
22+
// String FILE_PATH = "/Users/SteveSun/Google Drive/Developer/first50.txt";
23+
// String FILE_PATH = "/Users/SteveSun/Google Drive/Developer/first100.txt";
24+
// String FILE_PATH = "/Users/SteveSun/Google Drive/Developer/test.txt";
25+
26+
String OUTPUT_PATH = "/Users/SteveSun/Google Drive/Developer/output_wordsforproblem.txt";
27+
// String OUTPUT_PATH = "/Users/SteveSun/Google Drive/Developer/output_first30.txt";
28+
// String OUTPUT_PATH = "/Users/SteveSun/Google Drive/Developer/output_first50.txt";
29+
// String OUTPUT_PATH = "/Users/SteveSun/Google Drive/Developer/output_first1001.txt";
30+
// String OUTPUT_PATH = "/Users/SteveSun/Google Drive/Developer/output_testagain.txt";
31+
32+
ConcatenatedWordsII test = new ConcatenatedWordsII();
33+
ResultType result = test.readFromFile(FILE_PATH);
34+
Set<String> words = result.wordDict;
35+
Integer maxWordLen = result.maxWordLen;
36+
TrieNode root = test.buildTrie(words);
37+
long startTime = System.currentTimeMillis();
38+
List<String> validConcatenatedWords = new ArrayList();
39+
for (String word : words) {
40+
if (word == null || word.length() == 0) continue;
41+
test.remove(word, root);/** every word is comprised of every word itself, thus this word itself needs to be removed first for checking it*/
42+
int n = word.length();
43+
boolean[] dp = new boolean[n + 1];
44+
dp[0] = true;
45+
46+
for (int i = 1; i <= n; i++) {
47+
for (int j = 1; j <= i && j <= maxWordLen; j++) {
48+
if (!dp[i - j])
49+
continue;
50+
51+
String subWord = word.substring(i - j, i);
52+
if (test.contains(subWord, root)) {
53+
dp[i] = true;
54+
break;
55+
}
56+
}
57+
}
58+
59+
if(dp[n]) validConcatenatedWords.add(word);
60+
test.undoRemove(word, root);
61+
}
62+
long finishTime = System.currentTimeMillis();
63+
long usedTime = finishTime - startTime;
64+
65+
//Note: we're only interested in the first two longest words, so we can iterate through validConcatenatedWords once and find those two
66+
String firstLongest = "";
67+
String secondLongest = "";
68+
for(String word : validConcatenatedWords){
69+
if(word.length() > secondLongest.length()){
70+
if(word.length() > firstLongest.length()) {
71+
String temp = secondLongest;
72+
secondLongest = firstLongest;
73+
firstLongest = word;
74+
} else {
75+
secondLongest = word;
76+
}
77+
}
78+
}
79+
//print out the result we're interested in: longest concatenated word, second concatenated word, and the total number of all concatenated words
80+
System.out.println("The longest concatenated word is: " + firstLongest + ",\nthe 2nd longest concatenated word is: "+
81+
secondLongest + "\nand there are a total of " + validConcatenatedWords.size() + " valid concatenated words in this given file.");
82+
83+
//For a more verbose solution, I'm printing all words in descending order based on their lengths.
84+
sortAndWriteToFile(OUTPUT_PATH, validConcatenatedWords, usedTime);
85+
86+
} catch (Exception e) {
87+
e.printStackTrace();
88+
}
89+
}
90+
91+
private static void sortAndWriteToFile(String OUTPUT_PATH, List<String> validConcatenatedWords,
92+
long usedTime) throws IOException {
93+
Collections.sort(validConcatenatedWords, new Comparator<String>() {
94+
@Override
95+
public int compare(String o1, String o2) {
96+
if (o1.length() > o2.length()) {
97+
return -1;
98+
} else if (o1.length() < o2.length()) {
99+
return 1;
100+
} else {
101+
return 0;
102+
}
103+
}
104+
});
105+
106+
File file = new File(OUTPUT_PATH);
107+
108+
if (!file.exists())
109+
file.createNewFile();
110+
111+
FileWriter fw = new FileWriter(file.getAbsoluteFile());
112+
BufferedWriter bw = new BufferedWriter(fw);
113+
bw.write("There's a total of " + validConcatenatedWords.size() + " valid concatenated words found in this file.\n");
114+
bw.write("It took " + usedTime + " ms to finish.\n");
115+
for (String word : validConcatenatedWords) {
116+
bw.write(word + "\n");
117+
}
118+
119+
bw.close();
120+
}
121+
122+
public TrieNode buildTrie(Set<String> words) {
123+
TrieNode root = new TrieNode();
124+
for(String word : words){
125+
char[] chars = word.toCharArray();
126+
TrieNode node = root;
127+
for(int i = 0; i < chars.length; i++){
128+
char c = chars[i];
129+
if(node.children[c - 'a'] == null){
130+
node.children[c - 'a'] = new TrieNode();
131+
}
132+
node = node.children[c - 'a'];
133+
}
134+
node.isWord = true;
135+
}
136+
return root;
137+
}
138+
139+
// Returns true if the word is in the trie.
140+
public boolean contains(String word, TrieNode root) {
141+
TrieNode node = root;
142+
for(int i = 0; i < word.length(); i++){
143+
if(node.children[word.charAt(i) - 'a'] == null) return false;
144+
node = node.children[word.charAt(i) - 'a'];
145+
}
146+
return node.isWord;
147+
}
148+
149+
// mark that word on
150+
public void undoRemove(String word, TrieNode root) {
151+
TrieNode node = root;
152+
for(int i = 0; i < word.length(); i++){
153+
node = node.children[word.charAt(i) - 'a'];
154+
}
155+
node.isWord = true;
156+
}
157+
158+
// mark that word off, we are not really deleting that word
159+
public void remove(String word, TrieNode root) {
160+
TrieNode node = root;
161+
for(int i = 0; i < word.length(); i++){
162+
node = node.children[word.charAt(i) - 'a'];
163+
}
164+
node.isWord = false;
165+
}
166+
167+
class TrieNode {
168+
169+
boolean isWord;
170+
TrieNode[] children = new TrieNode[26];
171+
172+
// Initialize your data structure here.
173+
public TrieNode() {}
174+
}
175+
176+
class ResultType {
177+
Set<String> wordDict;
178+
Integer maxWordLen;
179+
180+
ResultType(Set<String> wordDict, Integer maxWordLen) {
181+
this.wordDict = wordDict;
182+
this.maxWordLen = maxWordLen;
183+
}
184+
}
185+
186+
public ResultType readFromFile(String filePath) throws Exception {
187+
Set<String> wordDict = new HashSet<>();
188+
int maxWordLen = Integer.MIN_VALUE;
189+
try {
190+
BufferedReader br = new BufferedReader(new FileReader(filePath));
191+
try {
192+
StringBuilder sb = new StringBuilder();
193+
String line = br.readLine();
194+
195+
while (line != null) {
196+
String word = new String(line);
197+
maxWordLen = (maxWordLen > word.length()) ? maxWordLen : word.length();
198+
if (word.length() != 0)
199+
wordDict.add(word.trim());
200+
line = br.readLine();
201+
}
202+
} finally {
203+
br.close();
204+
}
205+
} finally {
206+
// print out or log error information reading input files
207+
}
208+
ResultType result = new ResultType(wordDict, maxWordLen);
209+
return result;
210+
}
211+
}

0 commit comments

Comments
 (0)