剑指 Offer 12. 矩阵中的路径 - 力扣(LeetCode) (leetcode-cn.com)
目录
非递归写法(含注释)
class Solution {
enum class direction { N, U, D, L, R }; //null, up, down, left, right
struct Ltr { //记录每个位置的坐标,以及下一次应该检查的方向
int x, y;
direction dir;
Ltr(int X, int Y, direction d) : x(X), y(Y), dir(d) {}
};
public:
bool exist(vector<vector<char>>& board, string word) {
size_t Row = board.size(), Col = board[0].size();
vector<vector<bool>> visited(Row);
for (auto& r : visited) r = vector<bool>(Col);
for (int i = 0; i < Row; ++i) {
for (int j = 0; j < Col; ++j) {
if (board[i][j] == word[0]) { //如果在矩阵中找到了第一个字符
if (match(board, visited, word, i, j)) return true;
}
}
}
return false;
}
bool match(const vector<vector<char>>& board, vector<vector<bool>>& visited, const string& word, int x, int y) {
stack<Ltr> lstk; //记录已访问过的位置的栈
visited[x][y] = true;
int pathlength = 0; //当前路径的长度
direction dir = direction::U; //应该检查的方向
while (pathlength >= 0 && pathlength < word.length() - 1) {
switch (dir) {
case direction::U: //上
dir = direction::D; //检查完一个方向,无论匹配与否,都要转向下一个方向
if (matched(board, visited, word[pathlength + 1], x - 1, y)) { //pos位置表示已经匹配但还未进栈的位置,pos+1表示有待检查的位置
handle(lstk, x--, y, dir, pathlength); //处理lstk, dir和pos
break;
}
case direction::D: //下
dir = direction::L;
if (matched(board, visited, word[pathlength + 1], x + 1, y)) {
handle(lstk, x++, y, dir, pathlength);
break;
}
case direction::L: //左
dir = direction::R;
if (matched(board, visited, word[pathlength + 1], x, y - 1)) {
handle(lstk, x, y--, dir, pathlength);
break;
}
case direction::R: //右
dir = direction::N;
if (matched(board, visited, word[pathlength + 1], x, y + 1)) {
handle(lstk, x, y++, dir, pathlength);
break;
}
case direction::N:
visited[x][y] = false;
--pathlength;
if (!lstk.empty()) { //从栈中弹出上一个字符,接着上一个字符进行操作
x = lstk.top().x, y = lstk.top().y;
dir = lstk.top().dir;
lstk.pop();
}
}
}
return pathlength == word.length() - 1 ? true : false;
}
bool matched(const vector<vector<char>>& board, vector<vector<bool>>& visited, const char& c, const int& x, const int& y) {
if (x < 0 || x >= board.size() || y < 0 || y >= board[0].size()) return false; //下标越界
if (visited[x][y] || board[x][y] != c) return false; //已经检查过或者不匹配
visited[x][y] = true;
return true;
}
void handle(stack<Ltr>& stk, const int& x, const int& y, direction& dir, int& pathlength) {
++pathlength;
stk.push(Ltr(x, y, dir)); //当前字符的位置和下次回到该位置要继续检查的方向 进栈
dir = direction::U; //当前位置匹配之后要进行下一个位置的匹配,需要重置方向
}
};
运行结果
递归写法
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
int rows = board.size(), cols = board[0].size();
vector<vector<bool>> visited(rows);
for (auto& r : visited) r = vector<bool>(cols);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
int pathlength = 0;
if (hasPath(board, visited, i, j, word, pathlength)) return true;
}
}
return false;
}
bool hasPath(const vector <vector<char>>& board, vector<vector<bool>>& visited, int x, int y, const string& word, int& pathlength) {
if (word.length() == pathlength) return true;
bool has_path = false;
if (
(x >= 0 && y >= 0 && x < board.size() && y < board[0].size()) &&
!visited[x][y] && board[x][y] == word[pathlength]
) {
visited[x][y] = true;
++pathlength;
has_path = hasPath(board, visited, x - 1, y, word, pathlength) ||
hasPath(board, visited, x + 1, y, word, pathlength) ||
hasPath(board, visited, x, y - 1, word, pathlength) ||
hasPath(board, visited, x, y + 1, word, pathlength);
if (!has_path) {
visited[x][y] = false;
--pathlength;
}
}
return has_path;
}
};
运行结果