leetcode79_单词搜索_二维平面回溯法

1.  参考题解

作者:liweiwei1419
链接:https://leetcode-cn.com/problems/word-search/solution/zai-er-wei-ping-mian-shang-shi-yong-hui-su-fa-pyth/

2.  这是一个使用回溯算法解决的问题,涉及的知识点有 DFS 和状态重置

3. 说明:1、偏移量数组在二维平面内是经常使用的,可以把它的设置当做一个技巧,并且在这个问题中,偏移量数组内的 4 个偏移的顺序无关紧要.2. 设置状态数组visited判断该坐标的数值有无使用过,这是一个技巧.

4.先附上自己写的代码,尤其注意vector一定要传入地址,不然内存会爆炸.

class Solution {
public:
	int m, n;
	bool flag = false;
	//方向数组很关键.
	int d[4][2] = { { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 } };
	//判断坐标有无越界.
	bool legal(int x, int y) {
		return x >= 0 && x <= m - 1 && y >= 0 && y <= n - 1;
	}
	//一定记住传入vector时需要传入他的指针,不然内存会爆炸.
	bool backtrace(int i, int j, vector<vector<char>>& board, string word, int index, vector<vector<int>>& state) {
		//终止条件,如果到了word的长度,则return.
		if (index == word.length() - 1) {
			return board[i][j] == word[index];
		}
		if (board[i][j] == word[index]) {
			for (int num = 0; num < 4; num++) {
				if (legal(i + d[num][0], j + d[num][1])) {
					if (state[i + d[num][0]][j + d[num][1]] == 1)
						continue;
					state[i + d[num][0]][j + d[num][1]] = 1;
					flag = backtrace(i + d[num][0], j + d[num][1], board, word, index + 1, state);
					//回溯很重要.
					state[i + d[num][0]][j + d[num][1]] = 0;
				}
				if (flag == true)
					break;
			}
		}
		return flag;
	}
	bool exist(vector<vector<char>>& board, string word) {
		//注意边界条件.
		if (board.size() <= 0 || board[0].size() <= 0 ||
			word.length() > board.size()*board[0].size() || word.length() <= 0)
			return false;
		m = board.size(); n = board[0].size();
		//建立状态数组,指示该数值有无使用过,这是一个技巧.
		vector<vector<int>> state(m, vector<int>(n, 0));
		//搜索m,n大小的数组.
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				//我传入i,j时已经使用过他,因此需要将它的状态置为1.
				state[i][j] = 1;
				if (backtrace(i, j, board, word, 0, state))
					return true;
				//千万记住回溯的时候状态也要回溯,因为state是一个数组.
				state[i][j] = 0;
			}
		}
		return false;
	}
};

5. 大神的

//大神的
int dir[4][4] = { { -1,0 },{ 1,0 },{ 0,-1 },{ 0,1 } };

bool exist(vector<vector<char>>& board, string word) {
	int m = board.size();
	int n = board[0].size();
	vector<vector<bool>> visited(m, vector<bool>(n));
	for (int i = 0; i<m; i++) {
		for (int j = 0; j<n; j++) {
			if (dfs(i, j, 0, board, word, visited))
				return true;
		}
	}
	return false;
}

bool dfs(int x, int y, int index, vector<vector<char>>& board, string &word, vector<vector<bool>>& visited) {
	if (index == word.size() - 1) {
		return word[index] == board[x][y];
	}

	if (word[index] == board[x][y]) {
		//将当前的点设置为true,比我的简洁。
		//我的是将下一个点设置为true,这样还需要单独判断第一个点.
		//因此这个是我需要学习的地方.
		visited[x][y] = true;
		for (int i = 0; i<4; i++) {
			int new_x = x + dir[i][0];
			int new_y = y + dir[i][1];
			//判断下一个点是否可访问.
			if (new_x >= 0 && new_x<board.size() && new_y >= 0 && new_y<board[0].size() && !visited[new_x][new_y])
				if (dfs(new_x, new_y, index + 1, board, word, visited))
					return true;//直接return true.
		}
		visited[x][y] = false;//回溯

	}
	return false;
}

final : 标准模板

class Solution {
public:
    bool dfs(vector<vector<char>>& board, string word, int index, int i, int j) {
        if(index==word.length()) return true;
        if(i<0 || i>=board.size() || j<0 || j>=board[0].size()) return false;
        if(board[i][j]=='#') return false;
        if(board[i][j]!=word[index]) return false;
        index++;
        char tmp = board[i][j];
        board[i][j] = '#';
        bool res = dfs(board,word,index,i+1,j) || dfs(board,word,index,i-1,j) ||
        dfs(board,word,index,i,j-1) || dfs(board,word,index,i,j+1);
        board[i][j] = tmp;
        index--;
        return res;
    }
    bool exist(vector<vector<char>>& board, string word) {
        int m = board.size(), n = board[0].size();
        if(m==0 || n==0) return false;
        if(word.length()==0) return false;
        for(int i=0;i<m;i++) {
            for(int j=0;j<n;j++) {
                if(dfs(board,word,0,i,j)) return true;
            }
        }
        return false;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值