|
| 1 | +--- |
| 2 | +id: word-search |
| 3 | +title: Word Search(LeetCode) |
| 4 | +sidebar_label: 0079-Word Search |
| 5 | +tags: |
| 6 | + - Array |
| 7 | + - String |
| 8 | + - Backtracking |
| 9 | + - Matrix |
| 10 | +description: Given an m x n grid of characters board and a string word, return true if word exists in the grid. |
| 11 | +--- |
| 12 | + |
| 13 | +## Problem Statement |
| 14 | + |
| 15 | +Given an `m x n` grid of characters `board` and a string `word`, return `true` if `word` exists in the grid. |
| 16 | + |
| 17 | +The word can 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. |
| 18 | + |
| 19 | +### Examples |
| 20 | + |
| 21 | +**Example 1:** |
| 22 | + |
| 23 | + |
| 24 | + |
| 25 | +```plaintext |
| 26 | +Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED" |
| 27 | +Output: true |
| 28 | +``` |
| 29 | + |
| 30 | +**Example 2:** |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +```plaintext |
| 35 | +Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE" |
| 36 | +Output: true |
| 37 | +``` |
| 38 | + |
| 39 | +**Example 3:** |
| 40 | + |
| 41 | + |
| 42 | + |
| 43 | +```plaintext |
| 44 | +Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB" |
| 45 | +Output: false |
| 46 | +``` |
| 47 | + |
| 48 | +### Constraints |
| 49 | + |
| 50 | +- `m == board.length` |
| 51 | +- `n = board[i].length` |
| 52 | +- `1 <= m, n <= 6` |
| 53 | +- `1 <= word.length <= 15` |
| 54 | +- `board` and `word` consists of only lowercase and uppercase English letters. |
| 55 | + |
| 56 | +## Solution |
| 57 | + |
| 58 | +### Approach |
| 59 | + |
| 60 | +#### Algorithm |
| 61 | + |
| 62 | +1. Initialization: |
| 63 | +* Convert the input word to a character array `w`. |
| 64 | +* Iterate through each cell in the board using nested loops. |
| 65 | +2. Recursive Search: |
| 66 | +* For each cell in the board, call the recursive function `exist`. |
| 67 | +* The recursive function `exist` takes parameters: the board, current cell coordinates `(y, x)`, the word array, and the current index `i` in the word array. |
| 68 | +* Base cases: |
| 69 | + * If `i` equals the length of the word, return `true` (all characters are matched). |
| 70 | + * If the current cell `(y, x)` is out of bounds or does not match the current character in the word array, return `false`. |
| 71 | +* Mark the current cell as visited by toggling the 8th bit using `board[y][x] ^= 256`. |
| 72 | +* Recursively check all four possible directions (right, left, down, up) from the current cell. |
| 73 | +* After the recursive calls, unmark the current cell by toggling the 8th bit again using `board[y][x] ^= 256`. |
| 74 | +* Return `true` if any of the recursive calls return `true`, indicating that the word exists in the board starting from the current cell. |
| 75 | +3. Return Result: |
| 76 | +* Return `true` if the word is found starting from any cell, otherwise return `false`. |
| 77 | + |
| 78 | +#### Implementation |
| 79 | + |
| 80 | +```Java |
| 81 | +public boolean exist(char[][] board, String word) { |
| 82 | + char[] w = word.toCharArray(); |
| 83 | + for (int y=0; y<board.length; y++) { |
| 84 | + for (int x=0; x<board[y].length; x++) { |
| 85 | + if (exist(board, y, x, w, 0)) return true; |
| 86 | + } |
| 87 | + } |
| 88 | + return false; |
| 89 | +} |
| 90 | + |
| 91 | +private boolean exist(char[][] board, int y, int x, char[] word, int i) { |
| 92 | + if (i == word.length) return true; |
| 93 | + if (y<0 || x<0 || y == board.length || x == board[y].length) return false; |
| 94 | + if (board[y][x] != word[i]) return false; |
| 95 | + board[y][x] ^= 256; |
| 96 | + boolean exist = exist(board, y, x+1, word, i+1) |
| 97 | + || exist(board, y, x-1, word, i+1) |
| 98 | + || exist(board, y+1, x, word, i+1) |
| 99 | + || exist(board, y-1, x, word, i+1); |
| 100 | + board[y][x] ^= 256; |
| 101 | + return exist; |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +### Complexity Analysis |
| 106 | + |
| 107 | +- **Time complexity**: $O(N.3^L)$ |
| 108 | + * N is the number of cells in the board (i.e., board.length * board[0].length). |
| 109 | + * L is the length of the word. |
| 110 | + * Each cell can be a starting point, and from each cell, we explore up to 3 directions (since we cannot revisit the previous cell, reducing from 4 to 3). |
| 111 | + |
| 112 | +- **Space complexity**: O(L) |
| 113 | + * The recursion stack can go up to a depth of L, which is the length of the word. |
| 114 | + * No additional data structures are used that grow with input size (in-place modification of the board is used). |
| 115 | + |
| 116 | +### Conclusion |
| 117 | + |
| 118 | +This recursive solution effectively finds the word in the board by exploring all possible paths and backtracking when a path does not lead to the solution. By marking cells with a bitmask, it avoids using additional memory for visited states, making the algorithm space-efficient. The time complexity reflects the worst-case scenario of exploring all possible paths, while the space complexity is primarily driven by the depth of the recursion stack. This approach is both time and space-efficient, making it suitable for large boards and words. |
0 commit comments