Skip to content

Commit 48e488c

Browse files
authored
Merge pull request #1388 from tanyagupta01/word-search-ii
Create 0212-word-search-ii.md
2 parents 7a78c86 + 66678f0 commit 48e488c

File tree

1 file changed

+236
-0
lines changed

1 file changed

+236
-0
lines changed
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
---
2+
id: word-search-II
3+
title: Word Search II
4+
sidebar_label: 0212-word-search-ii
5+
tags:
6+
- Array
7+
- String
8+
- Backtracking
9+
- Trie
10+
- Matrix
11+
- C++
12+
- Java
13+
- Python
14+
description: "This document provides a solution to the Word Search II problem, where we need to return all words on the board, given an mXn board of characters and a list of strings words."
15+
---
16+
17+
## Problem
18+
19+
Given an `m x n` `board` of characters and a list of strings `words`, return all words on the board.
20+
21+
Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
22+
23+
### Examples
24+
25+
**Example 1:**
26+
27+
Input: board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
28+
Output: ["eat","oath"]
29+
30+
**Example 2:**
31+
32+
Input: board = [["a","b"],["c","d"]], words = ["abcb"]
33+
Output: []
34+
35+
### Constraints
36+
37+
- `m == board.length`
38+
- `n == board[i].length`
39+
- `1 <= m, n <= 12`
40+
- `board[i][j]` is a lowercase English letter.
41+
- `1 <= words.length <= 3 * 104`
42+
- `1 <= words[i].length <= 10`
43+
- `words[i]` consists of lowercase English letters.
44+
- All the strings of `words` are unique.
45+
46+
### Approach
47+
48+
The approach is very straightforward. After getting familiarized with trie data structure after you watch the above playlist, you will find implementing a trie, a very easy task. Hence let’s discuss the extra logic that comes into the picture here.
49+
50+
After you insert all the words into the trie, start doing a DFS at each position in the grid, standing at the root of the trie. At each step, check whether there exists a node attached to the alphabet corresponding to the one present in the grid. If yes, proceed to that particular node and in the grid, go to that particular alphabet cell. At each step, check whether the flag of that node is set to true or not. If it is true, then you know that you have reached the end of that particular word of the ‘words’ array. String ‘s’ will keep track of this string and it will be inserted into your ‘ans’ array. Array simply refers to vector, the dynamic array in C++.
51+
52+
This solution also employs a backtracking technique because you make a cell ‘*’ once you go to that so that the same character doesn’t repeat in the same word again and this change has to be reverted back once we have checked for that word so that you are not missing out on finding other words that are possibly associated with these changed characters. Also, it is not a good practice to modify the given input array when it’s passed by address.
53+
54+
### Solution
55+
56+
#### Code in Different Languages
57+
58+
### C++ Solution
59+
```cpp
60+
struct TrieNode {
61+
vector<shared_ptr<TrieNode>> children;
62+
const string* word = nullptr;
63+
TrieNode() : children(26) {}
64+
};
65+
66+
class Solution {
67+
public:
68+
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
69+
vector<string> ans;
70+
71+
for (const string& word : words)
72+
insert(word);
73+
74+
for (int i = 0; i < board.size(); ++i)
75+
for (int j = 0; j < board[0].size(); ++j)
76+
dfs(board, i, j, root, ans);
77+
78+
return ans;
79+
}
80+
81+
private:
82+
shared_ptr<TrieNode> root = make_shared<TrieNode>();
83+
84+
void insert(const string& word) {
85+
shared_ptr<TrieNode> node = root;
86+
for (const char c : word) {
87+
const int i = c - 'a';
88+
if (node->children[i] == nullptr)
89+
node->children[i] = make_shared<TrieNode>();
90+
node = node->children[i];
91+
}
92+
node->word = &word;
93+
}
94+
95+
void dfs(vector<vector<char>>& board, int i, int j, shared_ptr<TrieNode> node,
96+
vector<string>& ans) {
97+
if (i < 0 || i == board.size() || j < 0 || j == board[0].size())
98+
return;
99+
if (board[i][j] == '*')
100+
return;
101+
102+
const char c = board[i][j];
103+
shared_ptr<TrieNode> child = node->children[c - 'a'];
104+
if (child == nullptr)
105+
return;
106+
if (child->word != nullptr) {
107+
ans.push_back(*child->word);
108+
child->word = nullptr;
109+
}
110+
111+
board[i][j] = '*';
112+
dfs(board, i + 1, j, child, ans);
113+
dfs(board, i - 1, j, child, ans);
114+
dfs(board, i, j + 1, child, ans);
115+
dfs(board, i, j - 1, child, ans);
116+
board[i][j] = c;
117+
}
118+
};
119+
```
120+
### Java Solution
121+
```java
122+
class TrieNode {
123+
public TrieNode[] children = new TrieNode[26];
124+
public String word;
125+
}
126+
127+
class Solution {
128+
public List<String> findWords(char[][] board, String[] words) {
129+
for (final String word : words)
130+
insert(word);
131+
132+
List<String> ans = new ArrayList<>();
133+
134+
for (int i = 0; i < board.length; ++i)
135+
for (int j = 0; j < board[0].length; ++j)
136+
dfs(board, i, j, root, ans);
137+
138+
return ans;
139+
}
140+
141+
private TrieNode root = new TrieNode();
142+
143+
private void insert(final String word) {
144+
TrieNode node = root;
145+
for (final char c : word.toCharArray()) {
146+
final int i = c - 'a';
147+
if (node.children[i] == null)
148+
node.children[i] = new TrieNode();
149+
node = node.children[i];
150+
}
151+
node.word = word;
152+
}
153+
154+
private void dfs(char[][] board, int i, int j, TrieNode node, List<String> ans) {
155+
if (i < 0 || i == board.length || j < 0 || j == board[0].length)
156+
return;
157+
if (board[i][j] == '*')
158+
return;
159+
160+
final char c = board[i][j];
161+
TrieNode child = node.children[c - 'a'];
162+
if (child == null)
163+
return;
164+
if (child.word != null) {
165+
ans.add(child.word);
166+
child.word = null;
167+
}
168+
169+
board[i][j] = '*';
170+
dfs(board, i + 1, j, child, ans);
171+
dfs(board, i - 1, j, child, ans);
172+
dfs(board, i, j + 1, child, ans);
173+
dfs(board, i, j - 1, child, ans);
174+
board[i][j] = c;
175+
}
176+
}
177+
```
178+
### Python Solution
179+
180+
```python
181+
class TrieNode:
182+
def __init__(self):
183+
self.children: Dict[str, TrieNode] = {}
184+
self.word: Optional[str] = None
185+
186+
187+
class Solution:
188+
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
189+
m = len(board)
190+
n = len(board[0])
191+
ans = []
192+
root = TrieNode()
193+
194+
def insert(word: str) -> None:
195+
node = root
196+
for c in word:
197+
node = node.children.setdefault(c, TrieNode())
198+
node.word = word
199+
200+
for word in words:
201+
insert(word)
202+
203+
def dfs(i: int, j: int, node: TrieNode) -> None:
204+
if i < 0 or i == m or j < 0 or j == n:
205+
return
206+
if board[i][j] == '*':
207+
return
208+
209+
c = board[i][j]
210+
if c not in node.children:
211+
return
212+
213+
child = node.children[c]
214+
if child.word:
215+
ans.append(child.word)
216+
child.word = None
217+
218+
board[i][j] = '*'
219+
dfs(i + 1, j, child)
220+
dfs(i - 1, j, child)
221+
dfs(i, j + 1, child)
222+
dfs(i, j - 1, child)
223+
board[i][j] = c
224+
225+
for i in range(m):
226+
for j in range(n):
227+
dfs(i, j, root)
228+
229+
return ans
230+
```
231+
### Complexity Analysis
232+
**Time Complexity:** O(W * L)
233+
234+
>Reason: For each word in words, we insert each character into the Trie. If we assume the average length of a word is L and there are W words, this operation is O(W * L).
235+
236+
**Space Complexity:** O(M * N * M * N)

0 commit comments

Comments
 (0)