"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; } };