Skip to main content

Word Search II

Problem

Given an m x n board of characters and a list of strings words, return all words on the board.

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.

 

Example 1:

Input: board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]

Example 2:

Input: board = [["a","b"],["c","d"]], words = ["abcb"]
Output: []

 

Constraints:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 12
  • board[i][j] is a lowercase English letter.
  • 1 <= words.length <= 3 * 104
  • 1 <= words[i].length <= 10
  • words[i] consists of lowercase English letters.
  • All the strings of words are unique.

Solution

/**
* @param {character[][]} board
* @param {string[]} words
* @return {string[]}
*/
var findWords = function(board, words) {
const result = [];
const trie = new Trie();

for (const w of words) {
trie.insert(w);
}

for (let i = 0; i < board.length; i++) {
for (let j = 0; j < board[i].length; j++) {
dfs(board, trie.root, i, j, "", result);
}
}
return result;
};

var dfs = function(board, node, row, col, path, result) {
if (!node) { // path does not exist in trie
return;
}
if (node.end) { // path exist in trie
result.push(path);
node.end = false;
}
if (board?.[row]?.[col]) { // (row, rol) is not out of range and has not been used
const c = board[row][col];
node = node.children[c]
board[row][col] = null;
dfs(board, node, row + 1, col, path + c, result);
dfs(board, node, row - 1, col, path + c, result);
dfs(board, node, row, col + 1, path + c, result);
dfs(board, node, row, col - 1, path + c, result);
board[row][col] = c;
}
};

class Node {
constructor() {
this.end = false;
this.children = {};
}
}

class Trie {
constructor() {
this.root = new Node();
}

insert(word) {
let r = this.root;
for (const c of word) {
if (!(c in r.children)) {
r.children[c] = new Node();
}
r = r.children[c];
}
r.end = true;
}
}

We will implement a DFS backtracking solution with a trie. First, we insert all word in words into trie. Next, we iterate through all cells of board and apply DFS method dfs at (i, j), while also keeping track of the current path and node that we are on. Once we reach any point such that node has end = true, then we know path must exist in trie and so also exist in words (note that we also set end = false to prevent the same word from being added multiple times to res). In addition, to prevent re-using the same letter cell, set the cell to null before making any recursive calls (and revert it back before returning).