和剑指 Offer 12. 矩阵中的路径 - 力扣(LeetCode)相同
回溯法的使用,需要注意的点是起点的选择(需要遍历),以及如何避免死循环(走过的点就打上标记)
图来自:回溯算法求解 - 矩阵中的路径 - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> dirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
vector<vector<int>> visited;
bool exist(vector<vector<char>>& board, string word) {
int n = board.size(), m = board[0].size();
visited = vector<vector<int>>(n, vector<int>(m, 0));
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
//if(board[i][j] != word[0]) continue;//第一位就不等
if(dfs(board, word, 0, i, j)) return true;
}
}
return false;
}
bool dfs(vector<vector<char>>& board, string &word, int idx, int x, int y){
if(board[x][y] != word[idx]) return false; //当前字符不同
if(idx == word.size()-1) return true; //最后一个字符相同
visited[x][y] = 1;
for(const auto &dir : dirs){
if(x+dir[0] < 0 || x+dir[0] >= board.size() || y+dir[1] < 0 || y+dir[1] >= board[0].size()|| visited[x+dir[0]][y+dir[1]])
continue;
if(dfs(board, word, 1+idx, x+dir[0], y + dir[1])) return true;
}
visited[x][y] = 0;
return false;
}
};
idx传递只是起一个计数的作用,可以放在外围:
class Solution {
public:
vector<vector<int>> dirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
vector<vector<int>> visited;
int cnt = 0;
bool exist(vector<vector<char>>& board, string word) {
int n = board.size(), m = board[0].size();
visited = vector<vector<int>>(n, vector<int>(m, 0));
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
//if(board[i][j] != word[0]) continue;//第一位就不等
if(dfs(board, word, i, j)) return true;
}
}
return false;
}
bool dfs(vector<vector<char>>& board, string &word, int x, int y){
if(board[x][y] != word[cnt]) return false; //当前字符不同
if(cnt == word.size()-1) return true; //最后一个字符相同
++cnt;
visited[x][y] = 1;
for(const auto &dir : dirs){
if(x+dir[0] < 0 || x+dir[0] >= board.size() || y+dir[1] < 0 || y+dir[1] >= board[0].size()|| visited[x+dir[0]][y+dir[1]])
continue;
if(dfs(board, word, x+dir[0], y + dir[1])) return true;
}
--cnt;
visited[x][y] = 0;
return false;
}
};
另外也看到了不使用标记数组visited的方法:
class Solution {
public:
vector<vector<int>> dirs{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
bool exist(vector<vector<char>>& board, string word) {
int n = board.size(), m = board[0].size();
for(int i = 0; i < n; ++i){
for(int j = 0; j < m; ++j){
if(dfs(board, word, 0, i, j)) return true;
}
}
return false;
}
bool dfs(vector<vector<char>>& board, string &word, int idx, int x, int y){
if(board[x][y] != word[idx]) return false; //当前字符不同
if(idx == word.size()-1) return true; //最后一个字符相同
char tmp = board[x][y]; //临时存储
board[x][y] = 0; //可以避免这个位置重复使用
for(const auto &dir : dirs){
if(x+dir[0] < 0 || x+dir[0] >= board.size() || y+dir[1] < 0 || y+dir[1] >= board[0].size()) continue;
if(dfs(board, word, 1+idx, x+dir[0], y + dir[1])) return true;
}
board[x][y] = tmp; //复位
return false;
}
};