liuxuhelloworld's notebook

题目链接

https://leetcode-cn.com/problems/word-search/

解答过程

这个题目是挺久以前写的了,当时应该也是参考官方题解写的。重新看代码逻辑,有些地方就不太能理解。对代码进行了一些”优化“后,重新提交,测试未通过。单步跑报错的测试用例,恍然大悟,而且一定程度上让我更好地理解了遍历和回溯。一直比较困惑的一个问题就是,DFS和backtrack区别在哪呢?之前写的一些DFS和backtrack的题目,从代码看,真得很像,甚至有的backtrack标签的题目代码里方法名就是dfs. 我觉得DFS和backtrack比较显著的区别应该是在布尔标记数组的处理上,都经常用到布尔标记数组来标记遍历或回溯的过程,区别在于DFS往往是一次性的、单纯的标记某个元素是否已遍历到,而backtrack往往需要在递归返回后重置布尔标记数组,以避免影响后续的回溯。听起来有点抽象,随便挑几个用到了布尔标记数组的DFS和backtrack题目的代码看一下,就很好理解了。

	private int[] dx = new int[] {-1, 1, 0, 0};
	private int[] dy = new int[] {0, 0, -1, 1};

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

		boolean[][] tag = new boolean[m][n];

		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				if (board[i][j] == word.charAt(0)) {
					resetTag(tag);
					tag[i][j] = true;
					boolean exists = backtrack(board, i, j, word, 0, tag);
					if (exists) {
						return true;
					}
				}
			}
		}

		return false;
	}

	private void resetTag(boolean[][] tag) {
		for (int i = 0; i < tag.length; i++) {
			for (int j = 0; j < tag[0].length; j++) {
				if (tag[i][j]) {
					tag[i][j] = false;
				}
			}
		}
	}

	private boolean backtrack(char[][] board, int curRow, int curCol, String word, int curIdx, boolean[][] tag) {
		if (board[curRow][curCol] != word.charAt(curIdx)) {
			return false;
		}

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

		for (int i = 0; i < dx.length; i++) {
			int nextRow = curRow + dx[i];
			int nextCol = curCol + dy[i];
			if (isValidNextCell(nextRow, nextCol, word.charAt(curIdx+1), board, tag)) {
				tag[nextRow][nextCol] = true;
				boolean exists = backtrack(board, nextRow, nextCol, word,curIdx+1, tag);
				if (exists) {
					return true;
				}
				tag[nextRow][nextCol] = false;
			}
		}

		return false;
	}

	private boolean isValidNextCell(int nextRow, int nextCol, char nextCh, char[][] board, boolean[][] tag) {
		return isValidRow(nextRow, board.length)
			&& isValidCol(nextCol, board[0].length)
			&& tag[nextRow][nextCol] == false
			&& nextCh == board[nextRow][nextCol];
	}

	private boolean isValidRow(int row, int rowsNum) {
		return row >= 0 && row < rowsNum;
	}

	private boolean isValidCol(int col, int colsNum) {
		return col >= 0 && col < colsNum;
	}