1.题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
2.算法描述
方法:回溯法
在
矩
阵
中
任
选
一
个
格
子
作
为
路
径
的
起
点
。
在矩阵中任选一个格子作为路径的起点。
在矩阵中任选一个格子作为路径的起点。
如
果
探
索
的
路
径
上
的
第
i
个
字
符
不
是
c
h
,
那
么
这
个
格
子
不
可
能
处
在
真
正
路
径
上
的
第
i
个
位
置
。
\red{如果探索的路径上的第i个字符不是ch,那么这个格子不可能处在真正路径上的第i个位置。}
如果探索的路径上的第i个字符不是ch,那么这个格子不可能处在真正路径上的第i个位置。
如
果
探
索
的
路
径
上
的
第
i
个
字
符
正
好
是
c
h
,
那
么
往
相
邻
的
格
子
寻
找
真
正
路
径
上
的
第
i
+
1
个
字
符
。
\red{如果探索的路径上的第i个字符正好是ch,那么往相邻的格子寻找真正路径上的第i+1个字符。}
如果探索的路径上的第i个字符正好是ch,那么往相邻的格子寻找真正路径上的第i+1个字符。
除
在
矩
阵
边
界
上
的
格
子
之
外
,
其
他
格
子
都
有
4
个
相
邻
的
格
子
。
除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。
除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。
重
复
这
个
过
程
直
到
路
径
上
的
所
有
字
符
都
在
矩
阵
中
找
到
相
应
的
位
置
。
重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。
重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。
具体地:
1.
初
始
化
一
个
与
矩
阵
大
小
相
等
的
f
l
a
g
变
量
,
初
始
化
为
0
,
标
识
探
索
的
元
素
是
否
占
用
,
未
占
用
为
0
,
占
用
标
识
为
1
。
1.初始化一个\red{与矩阵大小相等的flag变量,初始化为0},标识探索的元素是否占用,未占用为0,占用标识为1。
1.初始化一个与矩阵大小相等的flag变量,初始化为0,标识探索的元素是否占用,未占用为0,占用标识为1。
2.
初
始
化
一
个
变
量
k
为
0
,
表
示
从
指
定
路
径
的
第
0
个
字
符
开
始
探
索
。
2.初始化一个\red{变量k为0},表示从指定路径的第0个字符开始探索。
2.初始化一个变量k为0,表示从指定路径的第0个字符开始探索。
3.
以
矩
阵
中
的
每
一
个
元
素
为
起
始
点
,
假
设
起
始
点
坐
标
(
矩
阵
坐
标
)
为
i
,
j
,
进
入
递
归
调
用
:
3.以矩阵中的每一个元素为起始点,假设起始点坐标(矩阵坐标)\red{为i,j},进入递归调用:
3.以矩阵中的每一个元素为起始点,假设起始点坐标(矩阵坐标)为i,j,进入递归调用:
若
i
,
j
不
在
合
理
范
围
,
或
探
索
的
元
素
已
经
被
占
用
,
或
探
索
的
元
素
与
路
径
中
元
素
不
等
,
则
探
索
的
路
径
走
不
通
返
回
f
a
l
s
e
。
\red{\ \ \ 若i,j不在合理范围,或探索的元素已经被占用,或探索的元素与路径中元素不等,则探索的路径走不通返回false。}
若i,j不在合理范围,或探索的元素已经被占用,或探索的元素与路径中元素不等,则探索的路径走不通返回false。
若
k
已
经
到
达
路
径
的
最
后
一
个
元
素
,
则
从
矩
阵
中
探
索
到
一
条
与
指
定
路
径
相
同
的
路
径
,
返
回
t
r
u
e
。
\red{\ \ \ 若k已经到达路径的最后一个元素,则从矩阵中探索到一条与指定路径相同的路径,返回true。}
若k已经到达路径的最后一个元素,则从矩阵中探索到一条与指定路径相同的路径,返回true。
把
i
,
j
的
标
识
更
改
为
1
,
标
识
占
用
。
\red{\ \ \ 把i,j的标识更改为1,标识占用。}
把i,j的标识更改为1,标识占用。
探
索
以
i
,
j
为
新
起
始
点
开
始
往
上
、
下
、
左
、
右
四
个
方
向
是
否
存
在
路
径
。
\red{\ \ \ 探索以i,j为新起始点开始往上、下、左、右四个方向是否存在路径。}
探索以i,j为新起始点开始往上、下、左、右四个方向是否存在路径。
把
i
,
j
的
标
识
更
改
为
0
,
回
溯
,
标
识
未
占
用
。
\red{\ \ \ 把i,j的标识更改为0,回溯,标识未占用。}
把i,j的标识更改为0,回溯,标识未占用。
3.代码描述
3.1.Java代码
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
int[] flag = new int[matrix.length];//用同等大小的标志变量标识矩阵中元素是否被占用 不能回头走
//对每一个可能的起始点开始递归
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
if(helper(matrix, str, flag, rows, cols, i, j, 0) == true)
return true;
return false;
}
private boolean helper(char[] matrix, char[] str, int[] flag, int rows, int cols, int i, int j, int k){
int index = cols * i + j;
//越界不行 当前元素已经被占用不行 当前元不等于路径元素不行
if(i<0 || i>=rows || j<0 || j>=cols || flag[index]==1 || matrix[index]!=str[k]) return false;
//只用确切地扫描到了路径的尾部 就是找到了路径
if(k == str.length-1) return true;
//当前元素标识为占用
flag[index] = 1;
if(helper(matrix, str, flag, rows, cols, i-1, j, k+1)||
helper(matrix, str, flag, rows, cols, i+1, j, k+1)||
helper(matrix, str, flag, rows, cols, i, j-1, k+1)||
helper(matrix, str, flag, rows, cols, i, j+1, k+1))
return true;
//如果上述没有返回true 回溯把标识换回来
flag[index] = 0;
return false;
}
}
3.2.Python代码
# -*- coding:utf-8 -*-
class Solution:
def hasPath(self, matrix, rows, cols, path):
flag = [0] * len(matrix)
for i in range(rows):
for j in range(cols):
if self.helper(matrix, path, flag, rows, cols, i, j, 0)==True:
return True
return False
def helper(self, matrix, path, flag, rows, cols, i, j, k):
idx = i * cols + j
if i<0 or i>=rows or j<0 or j>=cols or flag[idx]==1 or matrix[idx]!=path[k]:
return False
if k == len(path)-1:
return True
flag[idx] = 1
if (self.helper(matrix, path, flag, rows, cols, i-1, j, k+1)
or self.helper(matrix, path, flag, rows, cols, i+1, j, k+1)
or self.helper(matrix, path, flag, rows, cols, i, j-1, k+1)
or self.helper(matrix, path, flag, rows, cols, i, j+1, k+1)):
return True
else:
flag[idx] = 0
return False