"ABCESFCSADEE",3,4,"ABCCED"
true
"ABCESFCSADEE",3,4,"ABCB"
false
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//标志位,初始化为false
boolean[] flag = new boolean[matrix.length];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
//循环遍历二维数组,找到起点等于str第一个元素的值,再递归判断四周是否有符合条件的----回溯法
if(judge(matrix,i,j,rows,cols,flag,str,0)){
return true;
}
}
}
return false;
}
//judge(初始矩阵,索引行坐标i,索引纵坐标j,矩阵行数,矩阵列数,待判断的字符串,字符串索引初始为0即先判断字符串的第一位)
private boolean judge(char[] matrix,int i,int j,int rows,int cols,boolean[] flag,char[] str,int k){
//先根据i和j计算匹配的第一个元素转为一维数组的位置
int index = i*cols+j;
//递归终止条件
if(i<0 || j<0 || i>=rows || j>=cols || matrix[index] != str[k] || flag[index] == true)
return false;
//若k已经到达str末尾了,说明之前的都已经匹配成功了,直接返回true即可
if(k == str.length-1)
return true;
//要走的第一个位置置为true,表示已经走过了
flag[index] = true;
//回溯,递归寻找,每次找到了就给k加一,找不到,还原
if(judge(matrix,i-1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i+1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i,j-1,rows,cols,flag,str,k+1) ||
judge(matrix,i,j+1,rows,cols,flag,str,k+1) )
{
return true;
}
//走到这,说明这一条路不通,还原,再试其他的路径
flag[index] = false;
return false;
}
}
/**
用一个状态数组保存之前访问过的字符,然后再分别按上,下,左,右递归
*/
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, rows, cols, i, j, str, 0, flag))
return true;
}
}
return false;
}
private boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) {
int index = i * cols + j;
if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1)
return false;
if(k == str.length - 1) return true;
flag[index] = 1;
if (helper(matrix, rows, cols, i - 1, j, str, k + 1, flag)
|| helper(matrix, rows, cols, i + 1, j, str, k + 1, flag)
|| helper(matrix, rows, cols, i, j - 1, str, k + 1, flag)
|| helper(matrix, rows, cols, i, j + 1, str, k + 1, flag)) {
return true;
}
flag[index] = 0;
return false;
}
}
class Solution {
public:
/*
大家好,我是yishuihan,这个题目是回溯法的典型题目;
还有八皇后问题也是经典的回溯法例题,大家可以参考;在《剑指offer》书中也给出了八皇后问题的思路;
不过,那个是在全排列问题中引出来的。其实回溯法也是全排列的一种方案,在本题中,也就是尝试了
matrix矩阵中所有点作为起点的方法,然后依据这个点进行向四个方向的递归;
在递归中,不满足题目的会自动出栈回到上一个状态;
*/
bool hasPath(char* matrix, int rows, int cols, char* str)
{
if(matrix==NULL||rows<1||cols<1||str==NULL) return false;
bool *flag=new bool[rows*cols];
memset(flag,false,rows*cols);
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
if(haha(matrix,rows,cols,i, j,str,0,flag))
{
return true;
}
}
}
delete[] flag;
return false;
}
/*参数说明*/
bool haha(char* matrix,int rows,int cols,int i,int j,char* str,int k,bool* flag)
{
//因为是一维数组存放二维的值,index值就是相当于二维数组的(i,j)在一维数组的下标
int index = i * cols + j;
//flag[index]==true,说明被访问过了,那么也返回true;
if(i<0 || i>=rows || j<0 || j>=cols || matrix[index]!=str[k] || flag[index]==true)
return false;
//字符串已经查找结束,说明找到该路径了
if(str[k+1]=='\0') return true;
//向四个方向进行递归查找,向左,向右,向上,向下查找
flag[index] = true;//标记访问过
if( haha(matrix, rows, cols, i - 1, j, str, k + 1, flag)
||haha(matrix, rows, cols, i + 1, j, str, k + 1, flag)
||haha(matrix, rows, cols, i, j - 1, str, k + 1, flag)
||haha(matrix, rows, cols, i, j + 1, str, k + 1, flag))
{
return true;
}
flag[index] = false;
return false;
}
};
# -*- coding:utf-8 -*-
#回溯法
#遍历矩阵中的每一个位置
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
if not matrix:
return False
if not path:
return True
x = [list(matrix[cols*i:cols*i+cols]) for i in range(rows)]
for i in range(rows):
for j in range(cols):
if self.exist_helper(x, i, j, path):
return True
return False
def exist_helper(self, matrix, i, j, p):
if matrix[i][j] == p[0]:
if not p[1:]:
return True
matrix[i][j] = ''
if i > 0 and self.exist_helper(matrix, i-1, j, p[1:]):
return True
if i < len(matrix)-1 and self.exist_helper(matrix, i+1, j ,p[1:]):
return True
if j > 0 and self.exist_helper(matrix, i, j-1, p[1:]):
return True
if j < len(matrix[0])-1 and self.exist_helper(matrix, i, j+1, p[1:]):
return True
matrix[i][j] = p[0]
return False
else:
return False
# -*- coding:utf-8 -*-
class Solution:
def hasPath(self, board, row, col, word):
self.col, self.row = col, row
board = [list(board[col * i:col * i + col]) for i in range(row)]
for i in range(row):
for j in range(col):
if board[i][j] == word[0]:
self.b = False
self.search(board, word[1:], [(i, j)], i, j)
if self.b:
return True
return False
def search(self, board, word, dict, i, j):
if word == "":
self.b = True
return
if j != 0 and (i, j - 1) not in dict and board[i][j - 1] == word[0]:
self.search(board, word[1:], dict + [(i, j - 1)], i, j - 1)
if i != 0 and (i - 1, j) not in dict and board[i - 1][j] == word[0]:
self.search(board, word[1:], dict + [(i - 1, j)], i - 1, j)
if j != self.col - 1 and (i, j + 1) not in dict and board[i][j + 1] == word[0]:
self.search(board, word[1:], dict + [(i, j + 1)], i, j + 1)
if i != self.row - 1 and (i + 1, j) not in dict and board[i + 1][j] == word[0]:
self.search(board, word[1:], dict + [(i + 1, j)], i + 1, j)
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
if(matrix == null || matrix.length != rows * cols
|| str == null || str.length == 0
|| str.length > matrix.length) return false;
boolean[] visited = new boolean[matrix.length];
for (int j = 0; j < rows; j++) {
for (int i = 0; i < cols; i++) {//每个节点都有可能是起点
if(dfs(matrix,rows,cols,str,i,j,visited)) return true;
}
}
return false;
}
//这里方便遍历上下左右
private static int[] x = {0,1,0,-1};//顺时针
private static int[] y = {1,0,-1,0};//顺时针
//这里复用了boolean[] visited 减少内存开销
private boolean dfs(char[] matrix, int rows, int cols, char[] str, int i, int j, boolean[] visited) {
if(matrix[i + j * cols] != str[0]) return false;//第一个字符必须相等
Stack<Integer> s = new Stack<>();//存的是坐标
int index = 0;//当前str的索引
s.push(i + j * cols);
while(!s.empty()) {
int location = s.peek();
if(visited[location] == true){//访问过,全部复位
visited[location] = false;//取消访问记录
s.pop();//退出该节点
if(--index < 0) return false;
continue;//防止该路径再次遍历
}
visited[location] = true;//标记已访问
if(++index == str.length) return true;//如果这个字符恰好是最后一个字符,直接返回true
/*
* 将当前节点周围(上下左右)符合标准的点加入到s中,
* 1.边界条件:i = location % cols j = location / cols i和j判断边界
* 2.必须未遍历过visited[cur] == false
* 3.当前字符匹配matrix[cur] == str[index]
*/
for (int k = 0; k < 4; k++) {
int xn = location % cols + x[k];
int yn = location / cols + y[k];
int cur = xn + yn * cols;
if(xn >= 0 && xn < cols && yn >= 0
&& yn < rows && visited[cur] == false
&& matrix[cur] == str[index]) {
s.push(cur);
}
}
}
return false;
} public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
if(matrix == null || matrix.length != rows * cols
|| str == null || str.length == 0
|| str.length > matrix.length) return false;
boolean[] visited = new boolean[matrix.length];
for (int j = 0; j < rows; j++) {
for (int i = 0; i < cols; i++) {//每个节点都有可能是起点
if(dfs(matrix,rows,cols,str,i,j,0,visited)) return true;
}//这里多了个k=0来充当str的索引
}
return false;
}
//递归开始,真是短啊
private boolean dfs(char[] matrix, int rows, int cols, char[] str, int i, int j, int k,
boolean[] visited) {
if(i < 0 || i >= cols || j < 0 || j >= rows
|| visited[i + j * cols] || matrix[i + j * cols] != str[k])
return false;
if(k == str.length - 1) return true;//出口
visited[i + j * cols] = true;//递
if(dfs(matrix, rows, cols, str, i, j - 1, k + 1, visited)
|| dfs(matrix, rows, cols, str, i + 1, j, k + 1, visited)
|| dfs(matrix, rows, cols, str, i, j + 1, k + 1, visited)
|| dfs(matrix, rows, cols, str, i - 1, j, k + 1, visited))
return true;
visited[i + j * cols] = false;//归
return false;
}
//所谓的回溯无非就是对使用过的字符进行标记后和处理后的去标记
class Solution {
bool hasPathRecu(char* matrix, int rows, int cols, int row, int col, char *str, int length, vector<bool> used)
{
if(length==strlen(str))
return true;
if(row<0||row>=rows||col<0||col>=cols)
return false;
int index = col + row*cols;
bool result = false;
if( !used[index] && matrix[index]==str[length]){
used[index] = true;
result = hasPathRecu(matrix, rows, cols, row-1, col, str, length+1, used)|| hasPathRecu(matrix, rows, cols, row+1, col, str, length+1, used)
||hasPathRecu(matrix, rows, cols, row, col+1, str, length+1, used)||hasPathRecu(matrix, rows, cols, row, col-1, str, length+1, used);
used[index] = false;
}
if(result)
return true;
return false;
}
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
vector<bool> used(strlen(matrix),false);
if(str==NULL) return true;
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
if(hasPathRecu(matrix, rows, cols, i, j, str, 0, used))
return true;
}
}
return false;
}
};
public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
boolean[] visited = new boolean[matrix.length];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (searchFromHere(matrix,rows,cols,i,j,0,str,visited))
return true;
}
}
// System.out.println(Arrays.toString(visited));
return false;
}
public boolean searchFromHere(char[] matrix,int rows,int cols,int r,int c,int index,char[] str,boolean[] visited){
if (r < 0 || r >= rows || c < 0 || c >= cols || matrix[r * cols + c] != str[index] || visited[r * cols + c])
return false;
if (index == str.length - 1) return true;
visited[r * cols + c] = true;
if (searchFromHere(matrix,rows,cols,r - 1,c,index + 1,str,visited) ||
searchFromHere(matrix,rows,cols,r,c -1,index + 1,str,visited) ||
searchFromHere(matrix,rows,cols,r + 1,c,index + 1,str,visited) ||
searchFromHere(matrix,rows,cols,r,c + 1,index + 1,str,visited))
return true;
visited[r * cols + c] = false;
return false;
}
// private char[][] data;
// private int rows;
// private int cols;
// private LinkedList<Integer> path = new LinkedList<Integer>();
// private boolean result = false;
// private boolean isFinished = false;
//
// public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
// this.rows = rows;
// this.cols = cols;
// data = new char[rows][cols];
// for (int i = 0,k = 0; i < rows; i ++) {
// for (int j = 0; j < cols; j ++) {
// data[i][j] = matrix[k ++];
// }
// }
//
// int r,c;
// for (int i = 0; i < matrix.length; i++) {
// if (matrix[i] == str[0] && !isFinished){
// r = i / cols;
// c = i % cols;
// tryPath(r,c,str,0);
// }
// }
//
// return result;
// }
//
// public void tryPath(int r,int c,char[] str,int index){
// if (isFinished) return;
// if (path.contains(r * cols + c)) return;
//
// path.addLast(r * cols + c);
//
// if (index == str.length - 1) {
// isFinished = true;
// result = true;
// }
// else {
// for (int i = 0; i < 4; i++) {
// switch (i) {
// case 0:
// if (r - 1 >= 0 && data[r - 1][c] == str[index + 1]) {
// tryPath(r - 1, c, str, index + 1);
// }
// break;
// case 1:
// if (c - 1 >= 0 && data[r][c - 1] == str[index + 1]) {
// tryPath(r, c - 1, str, index + 1);
// }
// break;
// case 2:
// if (r + 1 < rows && data[r + 1][c] == str[index + 1]) {
// tryPath(r + 1, c, str, index + 1);
// }
// break;
// case 3:
// if (c + 1 < cols && data[r][c + 1] == str[index + 1]) {
// tryPath(r, c + 1, str, index + 1);
// }
// break;
// }
// }
// }
// path.removeLast();
// }
//思路:扫一遍矩阵 如果矩阵当前字符等于要查找的第一个字符,则从这个点dfs
// 详见代码注释
char maze[100][100]; //题目给的是char* matrix转换为二维char**maze
int vis[100][100]; //记录是否被访问过
int m,n;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0}; //四个方向
class Solution {
public:
void build(char* matrix,int rows,int cols) //建立二维的矩阵
{
int cnt=0;
for(int i=0;i<rows;++i)
for(int j=0;j<cols;++j)
maze[i][j]=matrix[cnt++];
}
//(x,y)表示当前坐标,des表示要查找的字符串,cnt表示已经匹配上了多少个
//len表示要查找的字符串的长度(好确定递归出口)
bool dfs(int x,int y,char *des,int cnt,int len)
{
if(cnt>=len) //出口
return true;
vis[x][y]=1;
for(int i=0;i<=3;++i)
{
int newx=x+dx[i],newy=y+dy[i];
if(vis[newx][newy]==0&&newx>=0&&newx<m&&newy>=0&&newy<n&&maze[newx][newy]==des[cnt])
{
if(dfs(newx,newy,des,cnt+1,len))
return true;
}
}
return false; //匹配失败
}
bool hasPath(char* matrix, int rows, int cols, char* str)
{
m=rows,n=cols;
build(matrix,rows,cols);
memset(vis,0,sizeof(vis));
for(int i=0;i<rows;++i) //遍历一遍,所以要记得重置vis数组
{
for(int j=0;j<cols;++j)
{
if(maze[i][j]==str[0]&&dfs(i,j,str,1,strlen(str)))
return true;
memset(vis,0,sizeof(vis)); //重置
}
}
return false;
}
};
//非递归法。由于一次只能出栈一个,且无法保证下一个的顺序,因此标记必须“随身携带”。
typedef pair<int, int> Pos;
struct State{
Pos p;
int s;
vector<int> vis;
State(Pos pos,int step,vector<int>visit) :
p(pos), s(step), vis(visit) {}
};
class Solution {
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
stack<State>q;
int maxS=strlen(str)-1;
vector<int> v(rows*cols,0);
//every start
for(int x=0;x<rows;x++)
for(int y=0;y<cols;y++){
if(matrix[x*cols+y]==str[0])
{
v[x*cols+y]=true;
q.push(State(Pos(x,y),0,v));
v[x*cols+y]=false;
}
}
while(!q.empty()){
//get
auto t=q.top();q.pop();
auto p=t.p;auto x=p.first,y=p.second; //position
auto s=t.s; //current step
auto vis=t.vis;
//operation
if(s==maxS)return true;
//next
for(int d=0;d<4;d++){
int nx=x+dx[d],ny=y+dy[d],ns=s+1;
if(nx>=0 && nx<rows && ny>=0 && ny<cols &&
ns<=maxS &&
matrix[nx*cols+ny]==str[ns] &&
!vis[nx*cols+ny]){
vis[nx*cols+ny]=true;
q.push(State(Pos(nx,ny),ns,vis));
}
}
}
return false;
}
};
//这道题是典型的深度优先遍历DFS的应用,原二维数组就像是一个迷宫,可以 //上下左右四个方向行走
//我们的二维数组board中每个数都作为起点和给定的字符串做匹配,我们需要
//一个和原二维数组board等大小的visited数组,是bool型的,用来记录当前位置
//是否被访问过。因为题目要求一个cell只能被访问一次。
//如果二维数组的当前字符和目标字符串str对应的字符相等,则对其上下左右四个邻字
//符串分别调用dfs的递归函数,只要有一个返回true,那么就表示找到对应的字符串
class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str)
{
if(str==NULL||rows<=0||cols<=0)
return false;
vector<vector<char>> board(rows, vector<char>(cols));
for(int i = 0; i < rows; ++i){//将matrix装入二维数组board中
for(int j = 0; j < cols; ++j){
board[i][j] = matrix[i*cols + j];
}
}
vector<vector<bool>> visited(rows,vector<bool>(cols, false));
for(int i = 0; i < rows; ++i){
for(int j = 0; j < cols; ++j){
if(dfs(board, str, 0, i, j, visited) == true)
return true;//以矩阵board中的每个字符为起点进行广度优先搜索
//找到一个符合条件的即返回true.
}
}
return false;//遍历完都没找到匹配的路径,返回false
}
private:
bool dfs(vector<vector<char>> board, char* str, int index, int x, int y,
vector<vector<bool>>& visited){
if(index == strlen(str))return true;//搜寻超过路径长度,符合条件,返回true
if((x < 0)||(y < 0)||(x >= board.size()) || (y >= board[0].size()))
return false;//访问越界,终止,返回false
if(visited[x][y]) return false;//之前访问过,剪枝
if(board[x][y] != str[index]) return false;//不相等,剪枝
visited[x][y] = true;
bool ret = dfs(board, str, index+1, x, y-1,visited)|| //上
dfs(board, str, index+1, x, y+1,visited)|| //下
dfs(board, str, index+1, x-1, y,visited)|| //左
dfs(board, str, index+1, x+1, y,visited); //右
visited[x][y] = false;//记得此处改回false,以方便下一次遍历搜索。
return ret;
}
};
function hasPath(matrix, rows, cols, path) {
const flags = new Array(matrix.length).fill(0);
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const index = i * cols + j;
if (matrix[index] === path[0]) { // 为起点开始
if (hasPathCore(matrix, rows, cols, path, flags, i, j, 0)) return true;
}
}
}
return false;
}
function hasPathCore(matrix, rows, cols, path, flags, i, j, k) {
let index = i * cols + j;
if (i < 0 || j < 0 || i >= rows || j >= cols || flags[index] || path[k] !== matrix[index]) {
return false;
}
if (path.length - 1 === k) {
return true;
}
flags[index] = 1;
if (hasPathCore(matrix, rows, cols, path, flags, i - 1, j, k + 1) ||
hasPathCore(matrix, rows, cols, path, flags, i + 1, j, k + 1) ||
hasPathCore(matrix, rows, cols, path, flags, i, j - 1, k + 1) ||
hasPathCore(matrix, rows, cols, path, flags, i, j + 1, k + 1)
) {
return true;
}
flags[index] = 0;
return false;
} # 基于深度优先遍历的方法
# 与原本的深度遍历不同的地方在于,除了当前路径的节点被标记为DISCOVERED,其他路径上的节点撤销该标记
def hasPath(self, matrix, rows, cols, path):
# write code here
self.discovered = {} # 维护矩阵中的节点是否遍历
self.tar = 0 # 维护要遍历到的path的位置
matrix = list(matrix)
matrix = [matrix[i*cols:i*cols+cols] for i in range(rows)] # 将输入的字符串复原为矩阵
def dfs(x,y): # 深度优先遍历的子函数,只有在遍历刚好结束于path的最后一个字符也相等的时候,返回TRUE
if x<0 or x==rows or y<0 or y==cols: # 如果坐标非法
return False
if (x,y) in self.discovered or matrix[x][y] != path[self.tar]: # 如果坐标已被访问或者坐标与应匹配字符串不同
return False
# 如果坐标合法且匹配正确
if self.tar == len(path) - 1: # 如果已经匹配到了最后一个字符
return True
# 匹配到中间字符,则继续向下遍历
self.discovered[x,y] = 1 # 标记当前坐标,防止重复访问
self.tar += 1 # 向后移动匹配位置
ret = dfs(x-1,y) or dfs(x+1,y) or dfs(x,y-1) or dfs(x,y+1) # 向四个方向进行深度优先遍历,确定匹配最终结果
# 当遍历返回的时候,重置该坐标的访问标志和path的匹配位置
self.discovered.pop((x,y))
self.tar -= 1
return ret
# 依次将每一个单元格作为遍历起点
for i in range(rows):
for j in range(cols):
if dfs(i,j):
return True
return False
#python 2.7 递归 时间:34ms 内存:5504k class Solution: def hasPath(self, matrix, rows, cols, path): for i, s in enumerate(matrix): if s==path[0] and self.visit([(i//cols, i%cols)], matrix, rows, cols, path): return True return False def visit(self, ans, matrix, rows, cols, path): if len(ans)==len(path): return True i,j = ans[-1] nex = [(ii,jj) for ii,jj in [(i,j-1),(i,j+1),(i-1,j),(i+1,j)] if 0<= ii <rows and 0<= jj <cols and (ii,jj) not in ans and matrix[ii*cols +jj]==path[len(ans)]] return sum([self.visit(ans+[x], matrix, rows, cols, path) for x in nex])
思路:
1.回溯经典题
2.本题首先要解决是如何理解这个输入,按道理来说是矩阵,但是给了一维数组
3.一开始也没有头绪,但是我们可以看到输入同时还给了行和列
4.但是一维数组为什么要给行和列?很明显是要我们自己构建二维数组
5.比如输入的是,martix={a,b,c,e,s,f,c,s,a,d,e,e},rows=3,cols=4
6.那么构建的二维数组就是:{{a,b,c,e},{s,f,c,s},{a,d,e,e}}
7.理解了这一点,现在有两种做法,一是我们自己创建这个二维数组
8.或者我们就使用原来的一维数组,通过公式index=i*cols+j,来计算元素的下标
9.我们知道回溯大部分题都会使用递归来解决问题
10.那首先找到递归的结束条件
11.每次递归可以走四个方向,每次都需判断是否等于要找的字符,且规定不能使用重复字符
12.递归的结束条件就是,不能越界,要满足字符相等,不能重复使用
13.然后找递归公式,很显然,就是分别走四个方向,每个方向都是一次递归 public static boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
//鲁棒
if (matrix.length < str.length || rows > matrix.length || cols > matrix.length) {
return false;
}
//构建一个和原一维数组大小相同的boolean数组,记录字符是否被使用过
boolean[] flag = new boolean[matrix.length];
//设置一个字符匹配数
int k = 0;
//间接的构建二维数组
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
//找到一组直接返回true
if (pathHelper(matrix, i, j, rows, cols, str, flag, k)) {
return true;
}
}
}
return false;
}
/**
* 通过不断的递归来寻路
*/
public static boolean pathHelper(char[] matrix, int i, int j, int rows, int cols
, char[] str, boolean[] flag, int k) {
//通过公式计算出二维数组在一维数组中的位置
int index = i * cols + j;
//1.递归结束条件
if (i < 0 || j < 0 || i >= rows || j >= cols || matrix[index] != str[k] || flag[index]) {
return false;
}
//如果刚好匹配完的话,直接返回true
if (k == str.length - 1) {
return true;
}
//开始回溯之前将本次回溯的字符标记位置为true,表示已经使用过了
flag[index] = true;
//开始回溯,上下左右分别回溯
if (pathHelper(matrix, i - 1, j, rows, cols, str, flag, k + 1) ||
pathHelper(matrix, i + 1, j, rows, cols, str, flag, k + 1) ||
pathHelper(matrix, i, j - 1, rows, cols, str, flag, k + 1) ||
pathHelper(matrix, i, j + 1, rows, cols, str, flag, k + 1)) {
return true;
}
//四个方向都没找到的话,说明当前字符不行,我们往回走,恢复flag
flag[index] = false;
return false;
} 回溯法,提前构造矩阵,参考剑指offer代码
# -*- coding:utf-8 -*-
class Solution:
def hasPath(self, matrix, rows, cols, path):
# write code here
if rows == 0 or cols == 0:
return False
self.build_matrix(matrix, rows, cols)
for i in range(rows):
for j in range(cols):
if self.find(i, j, 0, rows, cols, path):
return True
return False
def find(self, i, j, l, rows, cols, path):
if l == len(path):
return True
if i < 0 or i >= rows or j < 0 or j >= cols or self.flag[i][j] or self.new_matrix[i][j] != path[l]:
return False
self.flag[i][j] = 1
for n in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
if self.find(i+n[0], j+n[1], l+1, rows, cols, path):
return True
self.flag[i][j] = 0
return False
def build_matrix(self, matrix, rows, cols):
self.flag = []
self.new_matrix = []
for i in range(rows):
self.flag.append([0]*cols)
self.new_matrix.append(list(matrix[i*cols:cols+i*cols]))
# s = Solution()
# print(s.hasPath("ABCESFCSADEE", 3, 4, "ABCCED"))
// dfs遍历。。。
class Solution {
public:
bool dfs(char *matrix,char *str,int *visited,int rows,int cols,int r,int c,int l,int *stop){
if(*stop==1)return true;
int r1,c1,p;
int dr[]={-1,0,1,0};
int dc[]={0,1,0,-1};
p=r*cols+c;
visited[p]=1;
if(str[l+1]=='\0'){
*stop=1;
return true;
}
for(int i=0;i<4;i++){
r1=r+dr[i];
c1=c+dc[i];
if(r1<0||r1>=rows)continue;
if(c1<0||c1>=cols)continue;
p=r1*cols+c1;
if(!visited[p]&&str[l+1]==matrix[p]){
if(dfs(matrix,str,visited,rows,cols,r1,c1,l+1,stop))
return true;
}
}
return false;
}
bool hasPath(char* matrix, int rows, int cols, char* str)
{
int visited[rows*cols],p,stop;
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
p=i*cols+j;
if(matrix[p]==str[0]){
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
p=i*cols+j;
visited[p]=0;
}
}
stop=0;
if(dfs(matrix,str,visited,rows,cols,i,j,0,&stop)){return true;}
}
}
}
return false;
}
}; //回溯法,写了两种,注意flag矩阵的处理
//第一种
class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str) {
bool res = 0;
for (int i = 0;i<rows;++i) {
for (int j = 0;j<cols;++j) {
//bool *flag = (bool *)calloc(rows*cols, 1);
//vector<bool> flag(rows*cols,0);
bool *flag=new bool[rows*cols];
memset(flag,0,rows*cols);
res = dfs(matrix, rows, cols, i, j, flag, str);
if (res == true)
return res;
}
}
return res;
}
bool dfs(char* matrix, int rows, int cols, int i, int j, bool* flag, char* str) {
if (*(flag+i*cols + j) == 1 || (*(flag+i*cols + j) == 0 && *(matrix + i*cols + j) != *str))
return false;
else {
*(flag+i*cols + j) = 1;
if (*(str+1) == '\0')
return true;
bool res1 = 0, res2 = 0, res3 = 0, res4 = 0;
//左
if (j > 0 && j < cols)
res1 = dfs(matrix, rows, cols, i, j - 1, flag, str + 1);
//右
if (j >= 0 && j<cols - 1)
res2 = dfs(matrix, rows, cols, i, j + 1, flag, str+1);
//上
if (i>0 && i<rows)
res3 = dfs(matrix, rows, cols, i - 1, j, flag, str+1);
//下
if (i >= 0 && i<rows - 1)
res4 = dfs(matrix, rows, cols, i + 1, j, flag, str+1);
if(res1 || res2 || res3 || res4==0)
*(flag+i*cols + j)=0;
return res1 || res2 || res3 || res4;
}
}
};
//第二种,参照剑指offer简化了一下
class Solution {
public:
bool hasPath(char* matrix, int rows, int cols, char* str) {
bool res = 0;
bool *flag=new bool[rows*cols];
memset(flag,0,rows*cols);
for (int i = 0;i<rows;++i) {
for (int j = 0;j<cols;++j) {
//bool *flag = (bool *)calloc(rows*cols, 1);
res = dfs(matrix, rows, cols, i, j, flag, str);//1
if (res == true)
return res;
}
}
delete[] flag;
return res;
}
bool dfs(char* matrix, int rows, int cols, int i, int j, bool* flag, char* str) {
if (*str == '\0')
return true;
if(i<0||i>=rows||j<0||j>=cols)
return false;
if (*(flag+i*cols + j) == 1 || (*(flag+i*cols + j) == 0 && *(matrix + i*cols + j) != *str))
return false;
else {
*(flag+i*cols + j) = 1;
bool res=dfs(matrix, rows, cols, i, j - 1, flag, str + 1)//左
||dfs(matrix, rows, cols, i, j + 1, flag, str+1)//右
||dfs(matrix, rows, cols, i - 1, j, flag, str+1)//上
||dfs(matrix, rows, cols, i + 1, j, flag, str+1);//下
if(res==0)
*(flag+i*cols + j)=0;//这样从1处开始进入的DFS即使没找到路径,但是flag最后全部置为0
return res;
}
}
};
毋庸置疑最先想到回溯法。
说一个空间复杂度O(1)的。
走过的地块标为 ' ' 等不会用到的字符即可。
时间复杂度最差也不会到O(n2),没时间没能力算具体多少,总之实际上不太多。
类似的问题如:填海造陆,离陆最远等dfs,bfs问题。
多说两句说一下思路吧。数组存储的矩阵的任意一点(i,j)在数组中的位置k=i*cols+j
(btw,k在矩阵一点的位置(k/cols, k%cols))。
通过递归回溯,遍历数组,找从一点开始上下左右走且不重复的情况下,走出str路径的情况即可。
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
for (int i = 0; i < matrix.length; i++) {
if (findPath(matrix, cols, i, str, 0)) return true;
}
return false;
}
public boolean findPath(char[] matrix, int cols, int k, char[] str, int c) {
if (c >= str.length) return true;
if (k < 0 || k >= matrix.length || matrix[k] != str[c]) return false;
int i = k / cols;
int j = k % cols;
char tmp = matrix[k];
matrix[k] = ' ';
if (findPath(matrix, cols, (i-1)*cols+j, str, c+1) ||
findPath(matrix, cols, (i+1)*cols+j, str, c+1) ||
findPath(matrix, cols, i*cols+j-1, str, c+1) ||
findPath(matrix, cols, i*cols+j+1, str, c+1))
return true;
matrix[k] = tmp;
return false;
}
分析:回溯算法 这是一个可以用回朔法解决的典型题。首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的 第i个位置。如果路径上的第i个字符正好是ch,那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。 重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。 由于回朔法的递归特性,路径可以被开成一个栈。当在矩阵中定位了路径中前n个字符的位置之后,在与第n个字符对应的格子的周围都没有找到第n+1个 字符,这个时候只要在路径上回到第n-1个字符,重新定位第n个字符。 由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 当矩阵中坐标为(row,col)的 格子和路径字符串中相应的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下一个字符 如果4个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,我们需要回到前一个,然后重新定位。 一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置 class Solution { public: bool hasPath(char* matrix, int rows, int cols, char* str) { if(str==NULL||rows<=0||cols<=0) return false; bool *isOk=new bool[rows*cols](); for(int i=0;i<rows;i++) { for(int j=0;j<cols;j++) if(isHsaPath(matrix,rows,cols,str,isOk,i,j)) return true; } return false; } bool isHsaPath(char *matrix,int rows,int cols,char *str,bool *isOk,int curx,int cury) { if(*str=='\0') return true; if(cury==cols) { curx++; cury=0; } if(cury==-1) { curx--; cury=cols-1; } if(curx<0||curx>=rows) return false; if(isOk[curx*cols+cury]||*str!=matrix[curx*cols+cury]) return false; isOk[curx*cols+cury]=true; bool sign=isHsaPath(matrix,rows,cols,str+1,isOk,curx-1,cury) ||isHsaPath(matrix,rows,cols,str+1,isOk,curx+1,cury) ||isHsaPath(matrix,rows,cols,str+1,isOk,curx,cury-1) ||isHsaPath(matrix,rows,cols,str+1,isOk,curx,cury+1); isOk[curx*cols+cury]=false; return sign; } };