# Question

Formatted question description: https://leetcode.ca/all/79.html

Given an m x n grid of characters board and a string word, return true if word exists in the grid.

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.

Example 1:

Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
Output: true


Example 2:

Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
Output: true


Example 3:

Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
Output: false


Constraints:

• m == board.length
• n = board[i].length
• 1 <= m, n <= 6
• 1 <= word.length <= 15
• board and word consists of only lowercase and uppercase English letters.

Follow up: Could you use search pruning to make your solution faster with a larger board?

# Algorithm

This question is a typical application of depth-first traversal DFS. The original two-dimensional array is like a maze. You can walk in four directions. We use each number in the two-dimensional array as a starting point to match a given string. We also need a visited array of the same size as the original array, which is of bool type to record whether the current location has been visited, because the topic requires that a cell can only be visited once.

If the current character of the two-dimensional array board is equal to the character corresponding to the target string word, then the DFS recursive function is called respectively for the four adjacent characters of the upper, lower, left, and right directions. As long as one of them returns true, then the corresponding string can be found. Otherwise it can’t be found

# Code

• 
public class Word_Search {

public class Solution {

int m;
int n;

public boolean exist(char[][] board, String word) {
m = board.length;
n = board[0].length;

boolean result = false;

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dfs(board, word, i, j, 0)) {
return true;
}
}
}

return result;
}

public boolean dfs(char[][] board, String word, int i, int j, int wordPos) {

if (wordPos == word.length()) {
return true;
}

// @note: here, return check can remove the boundary check in each recursion, nice!
if (i < 0 || j < 0 || i >= m || j >= n || board[i][j] != word.charAt(wordPos)) {
return false;
}

char temp = board[i][j];

board[i][j] = '#';

boolean result = ( dfs(board, word, i - 1, j, wordPos + 1)
|| dfs(board, word, i + 1, j, wordPos + 1)
|| dfs(board, word, i, j - 1, wordPos + 1)
|| dfs(board, word, i, j + 1, wordPos + 1));

// restore from #
board[i][j] = temp;

return result;
}
}
}

############

class Solution {
public boolean exist(char[][] board, String word) {
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (dfs(i, j, 0, m, n, board, word)) {
return true;
}
}
}
return false;
}

private boolean dfs(int i, int j, int cur, int m, int n, char[][] board, String word) {
if (cur == word.length()) {
return true;
}
if (i < 0 || i >= m || j < 0 || j >= n || board[i][j] != word.charAt(cur)) {
return false;
}
board[i][j] += 256;
int[] dirs = {-1, 0, 1, 0, -1};
for (int k = 0; k < 4; ++k) {
int x = i + dirs[k];
int y = j + dirs[k + 1];
if (dfs(x, y, cur + 1, m, n, board, word)) {
return true;
}
}
board[i][j] -= 256;
return false;
}
}

• // OJ: https://leetcode.com/problems/word-search/
// Time: O(MN * 4^K)
// Space: O(K)
class Solution {
public:
bool exist(vector<vector<char>>& A, string s) {
int M = A.size(), N = A[0].size(), dirs[4][2] = { {0,1},{0,-1},{1,0},{-1,0} };
function<bool(int, int, int)> dfs = [&](int x, int y, int i) {
if (x < 0 || x >= M || y < 0 || y >= N || A[x][y] != s[i]) return false;
if (i + 1 == s.size()) return true;
char c = A[x][y];
A[x][y] = 0;
for (auto &[dx, dy] : dirs) {
if (dfs(x + dx, y + dy, i + 1)) return true;
}
A[x][y] = c;
return false;
};
for (int i = 0; i < M; ++i) {
for (int j = 0; j < N; ++j) {
if (dfs(i, j, 0)) return true;
}
}
return false;
}
};

• class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
def dfs(i, j, cur): # cur: current char count
if cur == len(word):
return True
if (
i < 0
or i >= m
or j < 0
or j >= n
or board[i][j] == '0'
or word[cur] != board[i][j]
):
return False
t = board[i][j]
board[i][j] = '0' # mark as visited
for a, b in [[0, 1], [0, -1], [-1, 0], [1, 0]]:
x, y = i + a, j + b
if dfs(x, y, cur + 1):
return True
board[i][j] = t
return False

m, n = len(board), len(board[0])
return any(dfs(i, j, 0) for i in range(m) for j in range(n))

############

class Solution:
# @param board, a list of lists of 1 length string
# @param word, a string
# @return a boolean
def exist(self, board, word):
if word == "":
return True
if len(board) == 0:
return False
visited = [[0] * len(board[0]) for i in range(0, len(board))]
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

def dfs(i, j, board, visited, word, index):
if word[index] != board[i][j]:
return False
if len(word) - 1 == index:
return True
for direction in directions:
ni, nj = i + direction[0], j + direction[1]
if ni >= 0 and ni < len(board) and nj >= 0 and nj < len(board[0]):
if visited[ni][nj] == 0:
visited[ni][nj] = 1
if dfs(ni, nj, board, visited, word, index + 1):
return True
visited[ni][nj] = 0
return False

for i in range(0, len(board)):
for j in range(0, len(board[0])):
visited[i][j] = 1
if dfs(i, j, board, visited, word, 0):
return True
visited[i][j] = 0
return False


• func exist(board [][]byte, word string) bool {
m, n := len(board), len(board[0])
var dfs func(i, j, cur int) bool
dfs = func(i, j, cur int) bool {
if cur == len(word) {
return true
}
if i < 0 || i >= m || j < 0 || j >= n || board[i][j] != word[cur] {
return false
}
t := board[i][j]
board[i][j] = '0'
dirs := []int{-1, 0, 1, 0, -1}
for k := 0; k < 4; k++ {
x, y := i+dirs[k], j+dirs[k+1]
if dfs(x, y, cur+1) {
return true
}
}
board[i][j] = t
return false
}
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if dfs(i, j, 0) {
return true
}
}
}
return false
}

• function exist(board: string[][], word: string): boolean {
let m = board.length,
n = board[0].length;
let visited = Array.from({ length: m }, v => new Array(n).fill(false));
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
if (dfs(board, word, i, j, 0, visited)) {
return true;
}
}
}
return false;
}

function dfs(
board: string[][],
word: string,
i: number,
j: number,
depth: number,
visited: boolean[][],
): boolean {
let m = board.length,
n = board[0].length;
if (i < 0 || i > m - 1 || j < 0 || j > n - 1 || visited[i][j]) {
return false;
}
if (board[i][j] != word.charAt(depth)) {
return false;
}

if (depth == word.length - 1) {
return true;
}

visited[i][j] = true;
++depth;
let res = false;
for (let [dx, dy] of [
[0, 1],
[0, -1],
[1, 0],
[-1, 0],
]) {
let x = i + dx,
y = j + dy;
res = res || dfs(board, word, x, y, depth, visited);
}
visited[i][j] = false;
return res;
}


• public class Solution {
public bool Exist(char[][] board, string word) {
var lenI = board.Length;
var lenJ = lenI == 0 ? 0 : board[0].Length;
var visited = new bool[lenI, lenJ];
for (var i = 0; i < lenI; ++i)
{
for (var j = 0; j < lenJ; ++j)
{
if (Search(board, visited, word, lenI, lenJ, i, j, 0))
{
return true;
}
}
}
return false;
}

private int[,] paths = new int[4,2] { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };

private bool Search(char[][] board, bool[,] visited, string word, int lenI, int lenJ, int i, int j, int p)
{
if (p == word.Length)
{
return true;
}
if (i < 0 || i >= lenI || j < 0 || j >= lenJ) return false;
if (visited[i, j] || word[p] != board[i][j]) return false;
visited[i, j] = true;
for (var k = 0; k < 4; ++k)
{
if (Search(board, visited, word, lenI, lenJ, i + paths[k, 0], j + paths[k, 1], p + 1)) return true;
}
visited[i, j] = false;
return false;
}
}

• impl Solution {
fn dfs(
i: usize,
j: usize,
c: usize,
word: &[u8],
board: &Vec<Vec<char>>,
vis: &mut Vec<Vec<bool>>,
) -> bool {
if board[i][j] as u8 != word[c] {
return false;
}
if c == word.len() - 1 {
return true;
}
vis[i][j] = true;
let dirs = [[-1, 0], [0, -1], [1, 0], [0, 1]];
for [x, y] in dirs.into_iter() {
// 索引合法性审核
let i = x + i as i32;
let j = y + j as i32;
if i < 0 || i == board.len() as i32 || j < 0 || j == board[0].len() as i32 {
continue;
}
let (i, j) = (i as usize, j as usize);
if !vis[i][j] && Self::dfs(i, j, c + 1, word, board, vis) {
return true;
}
}
vis[i][j] = false;
false
}

pub fn exist(board: Vec<Vec<char>>, word: String) -> bool {
let m = board.len();
let n = board[0].len();
let word = word.as_bytes();
let mut vis = vec![vec![false; n]; m];
for i in 0..m {
for j in 0..n {
if Self::dfs(i, j, 0, word, &board, &mut vis) {
return true;
}
}
}
false
}
}