🧠
Brute Force (Check Each Word Individually with DFS)
💡 This approach is the most straightforward: for each word, search the entire board to see if it exists. It is slow but helps understand the problem deeply before optimization.
Intuition
Try to find each word by starting a DFS from every cell in the board, checking if the word can be formed by adjacent letters.
Algorithm
- For each word in the list:
- For each cell in the board:
- Start a DFS to check if the word can be formed starting from that cell.
- If found, add the word to the result list.
💡 The nested loops and DFS make it hard to see the exponential time complexity at first glance.
from typing import List
class Solution:
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
if not board or not board[0] or not words:
return []
rows, cols = len(board), len(board[0])
result = []
def dfs(r, c, word, idx, visited):
if idx == len(word):
return True
if r < 0 or r >= rows or c < 0 or c >= cols:
return False
if (r, c) in visited or board[r][c] != word[idx]:
return False
visited.add((r, c))
res = (dfs(r+1, c, word, idx+1, visited) or dfs(r-1, c, word, idx+1, visited) or
dfs(r, c+1, word, idx+1, visited) or dfs(r, c-1, word, idx+1, visited))
visited.remove((r, c))
return res
for word in words:
found = False
for r in range(rows):
for c in range(cols):
if dfs(r, c, word, 0, set()):
result.append(word)
found = True
break
if found:
break
return result
# Driver code
if __name__ == '__main__':
board = [
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
]
words = ["oath","pea","eat","rain"]
sol = Solution()
print(sol.findWords(board, words))
Line Notes
def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:Main function to find all words by checking each word individually
if not board or not board[0] or not words:Handle empty board or empty words list edge cases
def dfs(r, c, word, idx, visited):DFS helper to check if a single word exists starting at (r,c)
if idx == len(word):Base case: all characters matched successfully
if (r, c) in visited or board[r][c] != word[idx]:Avoid revisiting cells and check character match
visited.add((r, c))Mark current cell as visited before exploring neighbors
visited.remove((r, c))Backtrack: unmark cell after exploring
for word in words:Iterate over all words to check individually
if dfs(r, c, word, 0, set()):If word found starting at this cell, add to result
return resultReturn all found words after checking all
import java.util.*;
public class Solution {
private int rows, cols;
private char[][] board;
private boolean[][] visited;
private String word;
public boolean dfs(int r, int c, int idx) {
if (idx == word.length()) return true;
if (r < 0 || r >= rows || c < 0 || c >= cols) return false;
if (visited[r][c] || board[r][c] != word.charAt(idx)) return false;
visited[r][c] = true;
boolean res = dfs(r+1, c, idx+1) || dfs(r-1, c, idx+1) || dfs(r, c+1, idx+1) || dfs(r, c-1, idx+1);
visited[r][c] = false;
return res;
}
public List<String> findWords(char[][] board, String[] words) {
this.board = board;
rows = board.length;
cols = board[0].length;
List<String> result = new ArrayList<>();
for (String w : words) {
this.word = w;
visited = new boolean[rows][cols];
boolean found = false;
for (int r = 0; r < rows && !found; r++) {
for (int c = 0; c < cols && !found; c++) {
if (dfs(r, c, 0)) {
result.add(w);
found = true;
}
}
}
}
return result;
}
// Driver code
public static void main(String[] args) {
Solution sol = new Solution();
char[][] board = {
{'o','a','a','n'},
{'e','t','a','e'},
{'i','h','k','r'},
{'i','f','l','v'}
};
String[] words = {"oath","pea","eat","rain"};
System.out.println(sol.findWords(board, words));
}
}
Line Notes
public boolean dfs(int r, int c, int idx)DFS helper to check if word exists starting at (r,c)
if (idx == word.length()) return true;All characters matched base case
visited[r][c] = true;Mark cell visited before recursion
visited[r][c] = false;Backtrack after recursion
for (String w : words)Iterate over each word to check
boolean found = false;Flag to stop searching once word found
if (dfs(r, c, 0))Start DFS from each cell
return result;Return list of found words
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Solution {
int rows, cols;
vector<vector<char>> board;
vector<vector<bool>> visited;
string word;
bool dfs(int r, int c, int idx) {
if (idx == word.size()) return true;
if (r < 0 || r >= rows || c < 0 || c >= cols) return false;
if (visited[r][c] || board[r][c] != word[idx]) return false;
visited[r][c] = true;
bool res = dfs(r+1, c, idx+1) || dfs(r-1, c, idx+1) || dfs(r, c+1, idx+1) || dfs(r, c-1, idx+1);
visited[r][c] = false;
return res;
}
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
this->board = board;
rows = board.size();
cols = board[0].size();
vector<string> result;
for (auto& w : words) {
word = w;
visited.assign(rows, vector<bool>(cols, false));
bool found = false;
for (int r = 0; r < rows && !found; r++) {
for (int c = 0; c < cols && !found; c++) {
if (dfs(r, c, 0)) {
result.push_back(w);
found = true;
}
}
}
}
return result;
}
};
// Driver code
int main() {
vector<vector<char>> board = {
{'o','a','a','n'},
{'e','t','a','e'},
{'i','h','k','r'},
{'i','f','l','v'}
};
vector<string> words = {"oath","pea","eat","rain"};
Solution sol;
vector<string> res = sol.findWords(board, words);
for (auto& w : res) cout << w << " ";
cout << endl;
return 0;
}
Line Notes
bool dfs(int r, int c, int idx)DFS function to check word existence from position
if (idx == word.size()) return true;Base case: all letters matched
visited[r][c] = true;Mark cell visited before exploring neighbors
visited[r][c] = false;Backtrack to allow other paths
for (auto& w : words)Check each word individually
bool found = false;Stop searching once word found
if (dfs(r, c, 0))Start DFS from each cell
return result;Return all found words
var findWords = function(board, words) {
const rows = board.length, cols = board[0].length;
const result = [];
function dfs(r, c, word, idx, visited) {
if (idx === word.length) return true;
if (r < 0 || r >= rows || c < 0 || c >= cols) return false;
if (visited.has(r + ',' + c) || board[r][c] !== word[idx]) return false;
visited.add(r + ',' + c);
const res = dfs(r+1, c, word, idx+1, visited) || dfs(r-1, c, word, idx+1, visited) || dfs(r, c+1, word, idx+1, visited) || dfs(r, c-1, word, idx+1, visited);
visited.delete(r + ',' + c);
return res;
}
for (const word of words) {
let found = false;
for (let r = 0; r < rows && !found; r++) {
for (let c = 0; c < cols && !found; c++) {
if (dfs(r, c, word, 0, new Set())) {
result.push(word);
found = true;
}
}
}
}
return result;
};
// Driver code
const board = [
['o','a','a','n'],
['e','t','a','e'],
['i','h','k','r'],
['i','f','l','v']
];
const words = ["oath","pea","eat","rain"];
console.log(findWords(board, words));
Line Notes
function dfs(r, c, word, idx, visited)DFS helper to check if word exists starting at (r,c)
if (idx === word.length) return true;All characters matched base case
visited.add(r + ',' + c);Mark cell visited before recursion
visited.delete(r + ',' + c);Backtrack after recursion
for (const word of words)Iterate over each word to check
if (dfs(r, c, word, 0, new Set()))Start DFS from each cell
return result;Return all found words
TimeO(W * N * 4^L) where W = number of words, N = number of cells, L = max word length
SpaceO(L) recursion stack + O(N) visited set
For each word, we start DFS from each cell. Each DFS explores up to 4 directions for each character, leading to exponential time in word length.
💡 For a 12x12 board (144 cells) and word length 10, this approach tries up to 4^10 paths per word, which is huge and impractical.
Interview Verdict: TLE
This approach is too slow for large inputs but is essential to understand the problem and motivate optimization.