题目:
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
示例:
board = [ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ] 给定 word = "ABCCED", 返回 true. 给定 word = "SEE", 返回 true. 给定 word = "ABCB", 返回 false.
每天更新一道python or C++ leetcode题,力求讲解清晰准确,客官们可以点赞或者关注。
算法过程:(主要见代码注释)
1.通过search函数的参数x, y记录当前搜索的位置,同时遍历上下左右方向,进入下一个位置。进入时要考虑下个位置是否符合标准。(详细解释见代码)
2.已搜索过的位置记为true,防止递归无法终止。搜索完后重新标记为false。
代码:
python:(看着吓人,实际逻辑很简单)
class Solution:
def __init__(self):
self.pos = list()#
self.n = self.m = 0#用来储存行和列的数目
self.flag = False#用来标志最终结果
self.l = 0#单词长度
self.target = ""#目标要构建的单词
self.direction = [[1,0],[-1,0],[0,1],[0,-1]]#可以选的方向
def search(self, board, x, y, s):
if s == self.target: self.flag = True; return#如果构建中的字符串达到目标要构建的单词
if len(s) >= self.l: return#如果构建的字符的长度大了,就返回,防止无限增加
self.pos[x][y] = True#把当前位置标记为已搜索,防止再次搜索。
for d in self.direction:#遍历所有方向,上下左右
if 0 <= x+d[0] <= self.n-1 and 0 <= y+d[1] <= self.m-1 and not self.pos[x+d[0]][y+d[1]] and board[x+d[0]][y+d[1]] == self.target[len(s)]:#只有当下个节点没有超过边界并且没有被访问过并且是下一个必须的组成单词的下一个字母时,我们才调用递归
self.search(board, x+d[0], y+d[1], s+board[x+d[0]][y+d[1]])#构建中的单词需要加上下一个字母,同时更新位置
if self.flag: return#如果找到了该单词,直接返回
self.pos[x][y] = False#把当前标为未访问
def exist(self, board, word):
self.n = len(board)#储存行数
if self.n == 0: return False
self.m = len(board[0])#储存列数
if self.m == 0: return False
self.l = len(word)#储存单词长度
if self.l == 0 or self.l > self.n*self.m: return False#如果当前单词比所有字母连一起还长
self.target = word#储存目标单词
self.pos = [[False for col in range(self.m)] for row in range(self.n)]#构建一个检测有没有被访问的表
for i in range(self.n):
for j in range(self.m):
if board[i][j] == word[0]:#如果当前字母等于第一个字母,开始递归
self.search(board,i,j,board[i][j])
return self.flag#返回最终结果
C++(写的相对简洁一点)
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
int row = board.size();
int col = board[0].size();
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
//visit数组记录该数组是否被访问过
vector<vector<bool>> visit(row, vector<bool>(col, false));
bool res = dfs(board, visit, i, j, word, 0);
if (res == true)
return true;
}
}
return false;
}
//index表示的是当前探索的是第几个词
bool dfs(vector<vector<char>>& b, vector<vector<bool>>& visit, int x, int y, //遍历数组的每一点
string s, int index)
{
int row = b.size();
int col = b[0].size();
if (index == s.length())
return true;
//以下几种情况 不再进行处理
//1、数组越界
//2、该节点已经访问过
//3、index位置的字符与字符串中的字符不符
else if (x < 0 || x >= row || y < 0 || y >= col //1
|| visit[x][y] == true //2
|| s[index]!=b[x][y]) //3
return false;
else
{
visit[x][y] = true;
//从xy出发向周围进行探索
bool x_1y = dfs(b, visit, x - 1, y, s, index + 1);
bool x1y = dfs(b, visit, x + 1, y, s, index + 1);
bool xy_1 = dfs(b, visit, x, y - 1, s, index + 1);
bool xy1 = dfs(b, visit, x, y + 1, s, index + 1);
if (x_1y || x1y || xy_1 || xy1)
return true;
else
{
visit[x][y] = false;
return false;
}
}
}
};
总结:
1.DFS可以通过记录当前位置来达到深搜目的
2.用visited 数组可以防止重复搜索,无法结束递归
3.注意剪枝