79. 单词搜索

单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例1:
在这里插入图片描述

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true

DFS + 回溯

思路:
我们已经确定使用 回溯 那么要回溯哪里,任何实现呢?

1、遍历数组,找到和 word 第一个字符相同的元素 (i,j),标志该元素已使用,找到了第一个,那么我们应该找第二个,最佳的方法就是向该元素的四周探寻,判断该元素的四周是否存在 word 的下一个字符。

2、我们知道了 入口 (i,j)使用递归来探寻(i,j)四周(上下左右)是否存在 word 的下一个字符,存在继续查找下一个,不存在直接返回,

3、综合上述可以得出:
①:遍历 board ,得到 (i,j)
②:递归 (i,j)的四个方向(上下左右),前提是 (i,j)包含 word 中第一个字符
③:记录已经比较过的字符,可以使用一个 boolean 二维数组或者在 board 中修改
④:递归完一个 (i,j)记得回溯,不然第一个(i,j)不符合,判断第二个的时候就会受影响。回溯的是 我们标记的 boolean 二维数组,或者 修改过的 board 也就是 ② 中标记的元素。

代码:

public static boolean exist(char[][] board, String word) {
		//回溯,让我们矩阵上的 i,j 	去探索其 上下左右,是否村咋,不存在下一个 i,j.不断探索,直到完成,使用过的单词标记
		int h = board.length, w = board[0].length;
		boolean[][] visited = new boolean[h][w];
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				if (check(board, visited, i, j, word, 0)) {
					return true;
				}
			}
		}
		return false;
	}

	public static boolean check(char[][] board, boolean[][] visited, int i, int j, String s, int k) {
		//是否存在,不存在直接返回false
		if (board[i][j] != s.charAt(k)) {
			return false;
		//k == s.length() -1 表示已经查找完毕,并且无 false,结束,直接返回 ture
		} else if (k == s.length() - 1) {
			return true;
		}
		visited[i][j] = true;
		//上下左右四个行走方向
		int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
		boolean result = false;
		for (int[] dir : directions) {
			//定义下一个探索的方向,i,j
			int newi = i + dir[0], newj = j + dir[1];
			//判断是否超出边界
			if (newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length) {
				//是否已经标记使用过该单词
				if (!visited[newi][newj]) {
					//进行下一个方向的查找,下一个单词,所以 k+1,方向 为 newi,newj
					boolean flag = check(board, visited, newi, newj, s, k + 1);
					//如果 找到下一个,结果设置为 ture 跳过当前循环,继续查找下一个
					if (flag) {
						result = true;
						break;
					}
				}
			}
		}
		//回溯,这个 i,j的上下左右不存在,可能下一个 i,j 的上下左右存在呢。
		visited[i][j] = false;
		return result;
	}

在原来数组中修改:

 public boolean exist(char[][] board, String word) {
       //回溯,让我们矩阵上的 i,j 	去探索其 上下左右,是否村咋,不存在下一个 i,j.不断探索,直到完成,使用过的单词标记
		int h = board.length, w = board[0].length;
		for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				if (check(board, i, j, word, 0)) {
					return true;
				}
			}
		}
		return false;
    }

  public static boolean check(char[][] board, int i, int j, String s, int k) {
		//判断是否存在,是否使用过,是否越界
		if ( i < 0 || i > board.length - 1 || j < 0 || j > board[0].length - 1 || board[i][j] == '.' || board[i][j] != s.charAt(k)) {
			return false;
		//k == s.length() -1 表示已经查找完毕,并且无 false,结束,直接返回 ture
		}  
        if (k == s.length() - 1) {
			return true;
		}else {
			char temp = board[i][j];
			//标记是否使用过
			board[i][j] = '.';
			//结合四个方向的判断结果,其中一个为 true 那么说明有匹配
			boolean res = check(board,i,j+1,s,k+1) || check(board,i,j-1,s,k+1) || check(board,i+1,j,s,k+1)  || check(board,i-1,j,s,k+1);
			//回溯
			board[i][j] = temp;
			return res;
	}
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值