-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathWordBreak2.java
345 lines (296 loc) · 11.8 KB
/
WordBreak2.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
package LeetCodeJava.BackTrack;
// https://leetcode.com/problems/word-break-ii/
import java.util.*;
/**
* 140. Word Break II
* Solved
* Hard
* Topics
* Companies
* Given a string s and a dictionary of strings wordDict, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences in any order.
*
* Note that the same word in the dictionary may be reused multiple times in the segmentation.
*
*
*
* Example 1:
*
* Input: s = "catsanddog", wordDict = ["cat","cats","and","sand","dog"]
* Output: ["cats and dog","cat sand dog"]
* Example 2:
*
* Input: s = "pineapplepenapple", wordDict = ["apple","pen","applepen","pine","pineapple"]
* Output: ["pine apple pen apple","pineapple pen apple","pine applepen apple"]
* Explanation: Note that you are allowed to reuse a dictionary word.
* Example 3:
*
* Input: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
* Output: []
*
*
* Constraints:
*
* 1 <= s.length <= 20
* 1 <= wordDict.length <= 1000
* 1 <= wordDict[i].length <= 10
* s and wordDict[i] consist of only lowercase English letters.
* All the strings of wordDict are unique.
* Input is generated in a way that the length of the answer doesn't exceed 105.
*
*/
public class WordBreak2 {
// V0
// public List<String> wordBreak(String s, List<String> wordDict) {
//
// }
// V0-1
// IDEA: BFS (fixed by gpt)
public class WordInfo {
int start_idx;
StringBuilder sb;
public WordInfo(int start_idx, StringBuilder sb) {
this.start_idx = start_idx;
this.sb = new StringBuilder(sb); // avoid mutation
}
}
List<String> wordBreak2Res = new ArrayList<>();
Set<String> wordDictSet;
public List<String> wordBreak_0_1(String s, List<String> wordDict) {
if (s == null || s.length() == 0 || wordDict == null || wordDict.isEmpty()) {
return wordBreak2Res;
}
wordDictSet = new HashSet<>(wordDict);
Queue<WordInfo> q = new LinkedList<>();
q.offer(new WordInfo(0, new StringBuilder()));
while (!q.isEmpty()) {
WordInfo info = q.poll();
int start = info.start_idx;
StringBuilder currentSb = info.sb;
if (start == s.length()) {
wordBreak2Res.add(currentSb.toString().trim());
continue;
}
for (String word : wordDictSet) {
int end = start + word.length();
if (end <= s.length() && s.substring(start, end).equals(word)) {
StringBuilder nextSb = new StringBuilder(currentSb);
/**
* is used to insert a space between words in the final sentence —
* but only if it's NOT the first word. (nextSb.length() > 0)
*
* -> below logic make sure ONLY add space
* when `NOT first word`
*/
if (nextSb.length() > 0){
nextSb.append(" ");
}
nextSb.append(word);
q.offer(new WordInfo(end, nextSb));
}
}
}
return wordBreak2Res;
}
// V1
// https://www.youtube.com/watch?v=QgLKdluDo08
// V2-1
// IDEA: Backtracking
// https://leetcode.com/problems/word-break-ii/editorial/
public List<String> wordBreak_2_1(String s, List<String> wordDict) {
// Convert wordDict to a set for O(1) lookups
Set<String> wordSet = new HashSet<>(wordDict);
List<String> results = new ArrayList<>();
// Start the backtracking process
backtrack(s, wordSet, new StringBuilder(), results, 0);
return results;
}
private void backtrack(
String s,
Set<String> wordSet,
StringBuilder currentSentence,
List<String> results,
int startIndex
) {
// If we've reached the end of the string, add the current sentence to results
if (startIndex == s.length()) {
results.add(currentSentence.toString().trim());
return;
}
// Iterate over possible end indices
for (
int endIndex = startIndex + 1;
endIndex <= s.length();
endIndex++
) {
String word = s.substring(startIndex, endIndex);
// If the word is in the set, proceed with backtracking
if (wordSet.contains(word)) {
int currentLength = currentSentence.length();
currentSentence.append(word).append(" ");
// Recursively call backtrack with the new end index
backtrack(s, wordSet, currentSentence, results, endIndex);
// Reset currentSentence to its original length
currentSentence.setLength(currentLength);
}
}
}
// V2-2
// IDEA: Dynamic Programming - Memoization
// https://leetcode.com/problems/word-break-ii/editorial/
// Main function to break the string into words
public List<String> wordBreak_2_2(String s, List<String> wordDict) {
Set<String> wordSet = new HashSet<>(wordDict);
Map<String, List<String>> memoization = new HashMap<>();
return dfs(s, wordSet, memoization);
}
// Depth-first search function to find all possible word break combinations
private List<String> dfs(
String remainingStr,
Set<String> wordSet,
Map<String, List<String>> memoization
) {
// Check if result for this substring is already memoized
if (memoization.containsKey(remainingStr)) {
return memoization.get(remainingStr);
}
// Base case: when the string is empty, return a list containing an empty string
if (remainingStr.isEmpty()) return Collections.singletonList("");
List<String> results = new ArrayList<>();
for (int i = 1; i <= remainingStr.length(); ++i) {
String currentWord = remainingStr.substring(0, i);
// If the current substring is a valid word
if (wordSet.contains(currentWord)) {
for (String nextWord : dfs(
remainingStr.substring(i),
wordSet,
memoization
)) {
// Append current word and next word with space in between if next word exists
results.add(
currentWord + (nextWord.isEmpty() ? "" : " ") + nextWord
);
}
}
}
// Memoize the results for the current substring
memoization.put(remainingStr, results);
return results;
}
// V2-3
// IDEA: Dynamic Programming - Tabulation
// https://leetcode.com/problems/word-break-ii/editorial/
public List<String> wordBreak_2_3(String s, List<String> wordDict) {
// Map to store results of subproblems
Map<Integer, List<String>> dp = new HashMap<>();
// Iterate from the end of the string to the beginning
for (int startIdx = s.length(); startIdx >= 0; startIdx--) {
// List to store valid sentences starting from startIdx
List<String> validSentences = new ArrayList<>();
// Iterate from startIdx to the end of the string
for (int endIdx = startIdx; endIdx < s.length(); endIdx++) {
// Extract substring from startIdx to endIdx
String currentWord = s.substring(startIdx, endIdx + 1);
// Check if the current substring is a valid word
if (isWordInDict(currentWord, wordDict)) {
// If it's the last word, add it as a valid sentence
if (endIdx == s.length() - 1) {
validSentences.add(currentWord);
} else {
// If it's not the last word, append it to each sentence formed by the remaining substring
List<String> sentencesFromNextIndex = dp.get(
endIdx + 1
);
for (String sentence : sentencesFromNextIndex) {
validSentences.add(currentWord + " " + sentence);
}
}
}
}
// Store the valid sentences in dp
dp.put(startIdx, validSentences);
}
// Return the sentences formed from the entire string
return dp.getOrDefault(0, new ArrayList<>());
}
// Helper function to check if a word is in the word dictionary
private boolean isWordInDict(String word, List<String> wordDict) {
return wordDict.contains(word);
}
// V2-4
// IDEA: Trie Optimization
// https://leetcode.com/problems/word-break-ii/editorial/
class TrieNode {
boolean isEnd;
TrieNode[] children;
TrieNode() {
isEnd = false;
children = new TrieNode[26];
}
}
class Trie {
TrieNode root;
Trie() {
root = new TrieNode();
}
void insert(String word) {
TrieNode node = root;
for (char c : word.toCharArray()) {
int index = c - 'a';
if (node.children[index] == null) {
node.children[index] = new TrieNode();
}
node = node.children[index];
}
node.isEnd = true;
}
}
public List<String> wordBreak_2_4(String s, List<String> wordDict) {
// Build the Trie from the word dictionary
Trie trie = new Trie();
for (String word : wordDict) {
trie.insert(word);
}
// Map to store results of subproblems
Map<Integer, List<String>> dp = new HashMap<>();
// Iterate from the end of the string to the beginning
for (int startIdx = s.length(); startIdx >= 0; startIdx--) {
// List to store valid sentences starting from startIdx
List<String> validSentences = new ArrayList<>();
// Initialize current node to the root of the trie
TrieNode currentNode = trie.root;
// Iterate from startIdx to the end of the string
for (int endIdx = startIdx; endIdx < s.length(); endIdx++) {
char c = s.charAt(endIdx);
int index = c - 'a';
// Check if the current character exists in the trie
if (currentNode.children[index] == null) {
break;
}
// Move to the next node in the trie
currentNode = currentNode.children[index];
// Check if we have found a valid word
if (currentNode.isEnd) {
String currentWord = s.substring(startIdx, endIdx + 1);
// If it's the last word, add it as a valid sentence
if (endIdx == s.length() - 1) {
validSentences.add(currentWord);
} else {
// If it's not the last word, append it to each sentence formed by the remaining substring
List<String> sentencesFromNextIndex = dp.get(
endIdx + 1
);
for (String sentence : sentencesFromNextIndex) {
validSentences.add(currentWord + " " + sentence);
}
}
}
}
// Store the valid sentences in dp
dp.put(startIdx, validSentences);
}
// Return the sentences formed from the entire string
return dp.getOrDefault(0, new ArrayList<>());
}
// V3
// V4
}