albertonline· portal
blind75

Solving Word Search II: Finding Words on a Board

Jan 26, 2024 · Exploring the solution to find all words from a given list that can be formed by traversing a grid of letters.

The "Word Search II" problem involves searching for all possible words from a given list within a grid of letters. This task requires efficiently traversing the grid and checking for the presence of words.

Problem Statement

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

Consider a board and a list of words:

Example 1 Input:

javascript

Output:

["eat", "oath"]

Example 2 Input:

javascript

Output:

[]

Solution Approach - Trie and Backtracking

typescript

Breaking Down the Solution


  • Trie for Word Storage: Store the list of words in a Trie for efficient searching.
  • Backtracking for Grid Traversal: Use depth-first search (DFS) with backtracking to explore the board.
  • Finding Words: On each step of DFS, check if the current path corresponds to a word in the Trie.

Conclusion


Word Search II is a challenging problem that combines Trie data structures with backtracking techniques, demonstrating advanced concepts in algorithm design and optimization.

Rust Solution

rust

Rust's #[derive(Default)] gives TrieNode::default() for free, so TrieNode::new is a one-line wrapper and the leaf's word: Option<String> starts as None rather than TS's string | null. The entry(c).or_insert_with(TrieNode::new) call collapses the has/set/get insertion dance into a single lookup that hands back a &mut TrieNode to descend into. Marking a hit uses next.word.take().unwrap(), which swaps the Some out and leaves None behind in one move — the same "clear so it isn't reported twice" step the TS version does with = null. Because i/j are usize, the neighbour offsets go through i as isize + dx and back via x as usize so a -1 step can't underflow, and the whole board threads through as &mut Vec<Vec<char>> so the '#' marking is visible across the recursion.

Go Solution

go

Go keys the trie with map[byte]*TrieNode, so children are looked up by the raw w[i] byte and each node is reached through a *TrieNode pointer rather than a value. The comma-ok form next, ok := node.children[c] distinguishes a real child from a missing one, and an empty-string sentinel replaces TS's null: a leaf is next.word != "" and is cleared with next.word = "" to avoid re-reporting. Collecting a hit does *result = append(*result, next.word), dereferencing the shared *[]string accumulator, and the caller finishes with sort.Strings(found). Note that board [][]byte is passed by value yet the '#' marking still sticks, because the slice header shares its backing array across the recursion.

Comments (0)

Stub comments live in your browser only (localStorage). No server round-trip yet.

No comments yet. Be the first.