Nikhil LearnHub
  • Home
  • Programming
    • C
    • C++
    • JAVA
    • PYTHON
    • Programming Hub
  • AI
    • AI HUB
    • NLP
  • Full Stack
    • Full Stack Hub
    • HTML
    • CSS
    • BOOTSTRAP
    • Java Script
    • Nodejs
    • Expressjs
    • Reactjs
  • Databases
    • Oracle
    • SQL Server
    • MySQL
    • MongoDB
  • More Tech
    • Problem solving hub
    • Engineer's Hub
    • Data Structures
    • Roadmaps
    • Cheatsheets
  1. Home
  2. Technology Hub
  3. Algorithms
  4. Word Search

Word Search

Given an M×N board of characters and a word, determine if the word exists by sequentially matching adjacent cells (horizontal or vertical). The classic solution uses DFS backtracking from every matching start cell, with a visited grid to prevent reusing the same cell. This lesson covers LeetCode 79 and implementations in C, Java, and Python with trace tables.

Table of Contents

  1. Overview
  2. Problem Statement
  3. Backtracking Algorithm
  4. Character Pruning
  5. Code (C, Java, Python)
  6. Output & Trace
  7. LeetCode 79 & 212
  8. Optimizations
  9. Approach Comparison
  10. Real-Life Applications
  11. Interview Tips
  12. Key Takeaway

Overview

Word Search is grid DFS with a string index instead of a path string. Each step checks whether the current cell matches the next character; if the full word matches, return true. Failed branches backtrack by unmarking visited cells.

Board (LeetCode 79 classic)          word = "ABCCED"

  A B C E                            (0,0)A → (0,1)B → (0,2)C
  S F C S         match path →       → (1,2)C → (2,2)E → (2,3)D  ✓
  A D E E

Adjacent moves only (no diagonals); each cell used once per path

Problem Statement

Input: 2D character board board[m][n] and string word.

Output: true if word can be constructed from sequentially adjacent cells; otherwise false.

Rules:

  • Letters must match in order along the word.
  • Only horizontal or vertical neighbors count (4-directional).
  • The same cell cannot appear twice in one search path.

Examples (classic board):

  • "ABCCED" → true
  • "SEE" → true (starts at (1,3) S)
  • "ABCB" → false (would need to reuse B at (0,1))

Backtracking Algorithm

  1. For each cell (row, col) where board[row][col] == word[0], run DFS.
  2. DFS(row, col, index):
    • If index == len(word), return true.
    • If out of bounds, visited, or char mismatch → return false.
    • Mark visited[row][col] = true.
    • Try four neighbors with index + 1; if any returns true, propagate.
    • Unmark visited and return false.
Same pattern as rat in a maze: mark → explore neighbors → unmark. Here the “path” is tracked by index into word, not a direction string.

Character Pruning

Before recursing, reject immediately when:

  • board[row][col] != word[index] — character mismatch
  • Cell already visited on current path
  • row or col out of bounds

In-place trick: Temporarily replace board[row][col] with '#' instead of a separate visited matrix — restore on backtrack (saves O(m×n) space).

Code (C, Java, Python)

Keywords Types Functions Variables Strings Numbers Comments

Python

def exist(board, word):
    """Word Search — DFS backtracking with visited grid."""
    if not board or not board[0]:
        return False
    rows, cols = len(board), len(board[0])
    visited = [[False] * cols for _ in range(rows)]
    dr = [1, -1, 0, 0]
    dc = [0, 0, 1, -1]

    def dfs(row, col, index):
        if index == len(word):
            return True
        if (row < 0 or row >= rows or col < 0 or col >= cols
                or visited[row][col] or board[row][col] != word[index]):
            return False
        visited[row][col] = True
        for k in range(4):
            if dfs(row + dr[k], col + dc[k], index + 1):
                return True
        visited[row][col] = False
        return False

    for r in range(rows):
        for c in range(cols):
            if board[r][c] == word[0] and dfs(r, c, 0):
                return True
    return False


if __name__ == "__main__":
    grid = [
        list("ABCE"),
        list("SFCS"),
        list("ADEE"),
    ]
    print(exist(grid, "ABCCED"))  # True
    print(exist(grid, "ABCB"))    # False

Java

public class WordSearch {

    private static final int[] DR = {1, -1, 0, 0};
    private static final int[] DC = {0, 0, 1, -1};

    private static boolean dfs(char[][] board, boolean[][] visited,
                               String word, int row, int col, int index) {
        if (index == word.length()) return true;
        if (row < 0 || row >= board.length || col < 0 || col >= board[0].length)
            return false;
        if (visited[row][col] || board[row][col] != word.charAt(index))
            return false;

        visited[row][col] = true;
        for (int k = 0; k < 4; k++) {
            if (dfs(board, visited, word, row + DR[k], col + DC[k], index + 1))
                return true;
        }
        visited[row][col] = false;
        return false;
    }

    public static boolean exist(char[][] board, String word) {
        int rows = board.length, cols = board[0].length;
        boolean[][] visited = new boolean[rows][cols];
        for (int r = 0; r < rows; r++)
            for (int c = 0; c < cols; c++)
                if (board[r][c] == word.charAt(0) && dfs(board, visited, word, r, c, 0))
                    return true;
        return false;
    }
}

C

#include <stdbool.h>
#include <string.h>

int dr[] = {1, -1, 0, 0};
int dc[] = {0, 0, 1, -1};

bool dfs(char board[][10], bool visited[][10], const char *word,
         int rows, int cols, int row, int col, int index) {
    int k, nr, nc;
    if (word[index] == '\0') return true;
    if (row < 0 || row >= rows || col < 0 || col >= cols) return false;
    if (visited[row][col] || board[row][col] != word[index]) return false;

    visited[row][col] = true;
    for (k = 0; k < 4; k++) {
        nr = row + dr[k];
        nc = col + dc[k];
        if (dfs(board, visited, word, rows, cols, nr, nc, index + 1))
            return true;
    }
    visited[row][col] = false;
    return false;
}

Output & Trace

Sample results (LeetCode board)

Word Result Reason
ABCCEDtruePath (0,0)→(0,1)→(0,2)→(1,2)→(2,2)→(2,3)
SEEtruePath (1,3)→(2,3)→(2,2)
ABCBfalseNeed B at (0,1) twice — cell reuse forbidden

Partial trace — matching "ABCCED"

Step Cell Char index Action
1(0,0)A0Start match, mark visited
2(0,1)B1Move right
3(0,2)C2Move right
4(1,2)C3Move down
5(2,2)E4Move down
6(2,3)D5Match complete → return true

LeetCode 79 & 212

Problem Task Approach
79 — Word SearchOne word exists?DFS backtracking from each start cell
212 — Word Search IIFind all words from a listTrie + DFS; prune when trie prefix dead

Optimizations

  • In-place visited: Mark cells with '#' — O(1) extra space beyond recursion.
  • Early return: Stop at first successful DFS — no need to search all starts after match.
  • Trie (LC 212): Share prefix exploration across many dictionary words.
  • Frequency prune: If board lacks enough of a rare letter, return false before DFS.

Approach Comparison

Approach Time Space Notes
DFS + visited[]O(m×n×4^L)O(L) recursion + O(m×n) visitedStandard LC 79
DFS in-place markSameO(L) recursionSpace-optimized
Trie + DFS (LC 212)Better for many wordsO(total chars in dict)Multi-word search

L = word length, m×n = board size.

Real-Life Applications

Domain Scenario Mapping
Word gamesBoggle, crossword helpersGrid letter + dictionary lookup
OCR / puzzlesFind hidden words in letter gridsSame DFS template
BioinformaticsSequence pattern in grids/matricesConstrained path matching
Search autocompletePrefix tree on 2D dataTrie extension of word search
InterviewsGrid DFS foundationLeads to island problems, maze, etc.

Interview Tips

  1. Clarify: 4-directional only, no cell reuse on one path.
  2. Loop all cells for first-char match, then DFS with index.
  3. Always unmark visited (or restore char) on backtrack.
  4. Mention in-place '#' trick if asked to optimize space.
  5. Complexity: O(m×n×4^L) worst case; L = word length.
  6. Connect to rat in a maze and pruning techniques.

Key Takeaway

Word Search = start DFS from each cell matching word[0]; at each step match word[index], mark visited, try four neighbors, unmark on failure. Character mismatch and visited cells are your pruning rules.

Track complete: Backtracking introduction · Algorithms Hub · Rat in a maze

Previous Backtracking introduction Algorithms Hub