forked from fishercoder1534/Leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
_472.java
155 lines (133 loc) · 4.99 KB
/
_472.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package com.fishercoder.solutions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class _472 {
public static class Solution1 {
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() {
}
}
}
public static class Solution2 {
public List<String> findAllConcatenatedWordsInADict(String[] words) {
List<String> result = new ArrayList<>();
Set<String> preWords = new HashSet<>();
/**Words could only be formed by other words that are shorter than itself, so we sort them based on their lengths first.*/
Arrays.sort(words, (s1, s2) -> s1.length() - s2.length());
for (int i = 0; i < words.length; i++) {
if (canForm(words[i], preWords)) {
result.add(words[i]);
}
preWords.add(words[i]);
}
return result;
}
boolean canForm(String word, Set<String> dict) {
if (dict.isEmpty()) {
return false;
}
boolean[] dp = new boolean[word.length() + 1];
dp[0] = true;
for (int i = 1; i <= word.length(); i++) {
for (int j = 0; j < i; j++) {
if (dp[j] && dict.contains(word.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[word.length()];
}
}
}