题意
给定一个m*n的矩阵,每个矩阵含有一个字母,求在矩阵中是否能搜索到特定的单词
Input: board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
Output: true
题目链接
https://leetcode.com/problems/word-search/description/
思考
这题一定是dfs,往四个方向搜索的经典题目
题解
遍历矩阵中的所有的元素,用dfs以遍历到的元素为起点搜索四个方向,并用vis数组确保已经访问过的节点不会被访问,如果搜索到的字符串能够构成word,那么就返回true
//初始位置没有单独计算
class Solution {
public:
int m = 0;
int n = 0;
bool exist(vector<vector<char>>& board, string word) {
m = board.size();
n = board[0].size();
vector<vector<bool>> vis(m, vector<bool>(n,false));
for(int i = 0; i < m; i++) {
f or(int j = 0; j < n; j++) {
if(dfs(board, word, i, j, vis,0)) {
return true;
}
}
}
return false;
}
bool dfs(vector<vector<char>>& board, string word, int x, int y, vector<vector<bool>>& vis, int u) {
//这里很容易错,如果改成u == word.size()是无法处理只有一个数字的
if (u == word.size() -1 && board[x][y] == word[u]) {
return true;
}
if(word[u] != board[x][y]) {
return false;
}
vis[x][y] = true;
int dk[] = {-1, 0, 1, 0, -1};
for(int i = 0; i < 4; i++) {
int nx = x + dk[i];
int ny = y + dk[i+1];
if(nx >= 0 && nx < m && ny >= 0 && ny < n && !vis[nx][ny] && dfs(board, word, nx, ny, vis, u+1)) {
return true;
}
}
vis[x][y] = false;
return false;
}
};
初始位置单独计算
class Solution {
public:
bool ret;
bool exist(vector<vector<char>>& board, string word) {
if(!word.size()) {
return true;
}
int m = board.size();
int n = board[0].size();
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(board[i][j] == word[0]) {
vector<vector<int>> vis(m, vector<int>(n,0));
vis[i][j] = 1;
dfs(board, 1, i, j, vis, word);
if(ret) {
return true;
}
}
}
}
return false;
}
void dfs(vector<vector<char>>& board, int st, int x, int y, vector<vector<int>>& vis, string word) {
int m = board.size();
int n = board[0].size();
if(st == word.size()) {
ret = true;
return;
}
int dk[] = {-1, 0, 1, 0, -1};
for(int i = 0; i < 4; i++) {
int dx = x + dk[i];
int dy = y + dk[i+1];
if(dx >= 0 && dx < m && dy >= 0 && dy < n && !vis[dx][dy] && board[dx][dy] == word[st]) {
vis[dx][dy] = 1;
dfs(board, st+1, dx, dy, vis, word);
vis[dx][dy] = 0;
}
}
}
};
question:为什么下面的代码过不了?以及有哪些不好的地方?
class Solution {
public:
bool ret;
bool exist(vector<vector<char>>& board, string word) {
if(!word.size()) {
return true;
}
int m = board.size();
int n = board[0].size();
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(board[i][j] == word[0]) {
vector<vector<int>> vis(m, vector<int>(n,0));
vis[i][j] = 1;
dfs(board, 1, i, j, vis, word);
if(ret) {
return true;
}
}
}
}
return false;
}
void dfs(vector<vector<char>>& board, int st, int x, int y, vector<vector<int>> vis, string word) {
int m = board.size();
int n = board[0].size();
if(st == word.size()) {
ret = true;
return;
}
int dk[] = {-1, 0, 1, 0, -1};
for(int i = 0; i < 4; i++) {
int dx = x + dk[i];
int dy = y + dk[i+1];
if(dx >= 0 && dx < m && dy >= 0 && dy < n && !vis[dx][dy] && board[dx][dy] == word[st]) {
vis[dx][dy] = 1;
dfs(board, st+1, dx, dy, vis, word);
vis[dx][dy] = 0;
}
}
}
};
为什么过不了?因为vis数组产生了copy,这个开销是MN的,你的答案的算法复杂度会变成M2N2
并且这个ret完全没必要,你完全可以通过dfs的返回值消掉这个ret
而且vis数组其实可以写在里面的
question:为什么这个会有问题?因为board[dx][dy] == word[st+1]
会有越界问题的,要想输入dfs(board, 0, i, j, vis, word
,我必须每次进入的时候判定,而不是说每一次for循环中去判定
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
if(!word.size()) {
return true;
}
int m = board.size();
int n = board[0].size();
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(board[i][j] == word[0]) {
vector<vector<int>> vis(m, vector<int>(n,0));
if(dfs(board, 0, i, j, vis, word)) {
return true;
}
}
}
}
return false;
}
bool dfs(vector<vector<char>>& board, int st, int x, int y, vector<vector<int>>& vis, string word) {
int m = board.size();
int n = board[0].size();
vis[x][y] = 1;
if(st == word.size()) {
return true;
}
int dk[] = {-1, 0, 1, 0, -1};
for(int i = 0; i < 4; i++) {
int dx = x + dk[i];
int dy = y + dk[i+1];
if(dx >= 0 && dx < m && dy >= 0 && dy < n && !vis[dx][dy] && board[dx][dy] == word[st+1]) {
if(dfs(board, st+1, dx, dy, vis, word)) {
return true;
}
}
}
vis[x][y] = 0;
return false;
}
};
最为简洁的写法,写的时候注意,先判断true,再来false
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
if(!word.size()) {
return true;
}
int m = board.size();
int n = board[0].size();
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(board[i][j] == word[0]) {
vector<vector<int>> vis(m, vector<int>(n,0));
if(dfs(board, 0, i, j, vis, word)) {
return true;
}
}
}
}
return false;
}
bool dfs(vector<vector<char>>& board, int st, int x, int y, vector<vector<int>>& vis, string word) {
int m = board.size();
int n = board[0].size();
if(st == word.size()) {
return true;
}
if(x < 0 || x >= m || y < 0 || y >= n) {
return false;
}
if(vis[x][y] || board[x][y] != word[st]) {
return false;
}
vis[x][y] = 1;
int dk[] = {-1, 0, 1, 0, -1};
for(int i = 0; i < 4; i++) {
int dx = x + dk[i];
int dy = y + dk[i+1];
if(dfs(board, st+1, dx, dy, vis, word)) {
return true;
}
}
vis[x][y] = 0;
return false;
}
};
时间复杂度
O
(
M
∗
N
∗
3
L
)
O(M*N*3^L)
O(M∗N∗3L)M是二维矩阵的长度,N是二维矩阵的宽度,L是单词的长度。
MN是因为外面的两层for循环,
3
L
3^L
3L是因为dfs搜索长度为L的字符串,有3个方向可以搜索(去除了回退哪一个)
空间复杂度
O
(
M
N
+
L
)
O(MN + L)
O(MN+L)