forked from fishercoder1534/Leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConcatenatedWords.java
127 lines (104 loc) · 3.4 KB
/
ConcatenatedWords.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package com.fishercoder.solutions;
import java.util.ArrayList;
import java.util.List;
/**
* Given a list of words, please write a program that returns all concatenated words in the given list of words.
A concatenated word is defined as a string that is comprised entirely of at least two shorter words in the given array.
Example:
Input: ["cat","cats","catsdogcats","dog","dogcatsdog","hippopotamuses","rat","ratcatdogcat"]
Output: ["catsdogcats","dogcatsdog","ratcatdogcat"]
Explanation: "catsdogcats" can be concatenated by "cats", "dog" and "cats";
"dogcatsdog" can be concatenated by "dog", "cats" and "dog";
"ratcatdogcat" can be concatenated by "rat", "cat", "dog" and "cat".
Note:
The number of elements of the given array will not exceed 10,000
The length sum of elements in the given array will not exceed 600,000.
All the input string will only include lower case letters.
The returned elements order does not matter.
*/
public class ConcatenatedWords {
private TrieNode root;
private int maxWordLen;
public List<String> findAllConcatenatedWordsInADict(String[] words) {
ResultType result = buildTrie(words);
root = result.root;
maxWordLen = result.maxWordLen;
List<String> validConcatenatedWords = new ArrayList();
for (String word : words) {
if (word == null || word.length() == 0) continue;
remove(word, root);/** every word is comprised of every word itself, thus this word itself needs to be removed first for checking it*/
int n = word.length();
boolean[] dp = new boolean[n + 1];
dp[0] = true;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i && j <= maxWordLen; j++) {
if (!dp[i - j])
continue;
String subWord = word.substring(i - j, i);
if (contains(subWord, root)) {
dp[i] = true;
break;
}
}
}
if(dp[n]) validConcatenatedWords.add(word);
undoRemove(word, root);
}
return validConcatenatedWords;
}
public ResultType buildTrie(String[] words) {
ResultType result = new ResultType();
TrieNode root = new TrieNode();
int maxWordLen = 0;
for(String word : words){
maxWordLen = Math.max(maxWordLen, word.length());
char[] chars = word.toCharArray();
TrieNode node = root;
for(int i = 0; i < chars.length; i++){
char c = chars[i];
if(node.children[c - 'a'] == null){
node.children[c - 'a'] = new TrieNode();
}
node = node.children[c - 'a'];
}
node.isWord = true;
}
result.root = root;
result.maxWordLen = maxWordLen;
return result;
}
public class ResultType{
int maxWordLen;
TrieNode root;
}
// Returns true if the word is in the trie.
public boolean contains(String word, TrieNode root) {
TrieNode node = root;
for(int i = 0; i < word.length(); i++){
if(node.children[word.charAt(i) - 'a'] == null) return false;
node = node.children[word.charAt(i) - 'a'];
}
return node.isWord;
}
// mark that word on
public void undoRemove(String word, TrieNode root) {
TrieNode node = root;
for(int i = 0; i < word.length(); i++){
node = node.children[word.charAt(i) - 'a'];
}
node.isWord = true;
}
// mark that word off, we are not really deleting that word
public void remove(String word, TrieNode root) {
TrieNode node = root;
for(int i = 0; i < word.length(); i++){
node = node.children[word.charAt(i) - 'a'];
}
node.isWord = false;
}
class TrieNode {
boolean isWord;
TrieNode[] children = new TrieNode[26];
public TrieNode() {}
}
}