算法准备-4.12
1. 矩阵中的路径
-
描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。
[[“a”,“b”,“c”,“e”],
[“s”,“f”,“c”,“s”],
[“a”,“d”,“e”,“e”]]但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。
-
思路:首先要把字符串转化为字符数组,检查第一个字符在矩阵中的位置,保存其横纵坐标,创建一个与输入矩阵同宽高的矩阵,初始值为0,每遍历一个,对应坐标的值变为1,检查他与字符串中对应的字符,相同则继续递归调用,不同则返回
-
题解:
class Solution { public boolean exist(char[][] board, String word) { char[] wordarray=word.toCharArray(); for(int i=0;i<board.length;i++) { for(int j=0;j<board[0].length;j++) { if(dfs(board,wordarray,i,j,0)) { return true; } } } return false; } public boolean dfs(char[][] board,char[] wordarray,int i,int j,int k){ if(i>=board.length||i<0||j<0||j>=board[0].length||wordarray[k]!=board[i][j]) { return false; } if(k==wordarray.length-1) { return true; } char temp=board[i][j]; board[i][j]='/'; boolean res=dfs(board,wordarray,i+1,j,k+1)||dfs(board,wordarray,i,j+1,k+1)||dfs(board,wordarray,i-1,j,k+1)||dfs(board,wordarray,i,j-1,k+1); board[i][j]=temp; return res; } }
注:这里面检测已走过的路径是将char矩阵中的额值变为/,不可能和字符相等,也可以用多一个数组来存储
class Solution { public boolean exist(char[][] board, String word) { char[] wordarray=word.toCharArray(); int[][] flag=new int[board.length][board[0].length]; for(int i=0;i<board.length;i++) { for(int j=0;j<board[0].length;j++) { if(dfs(board,wordarray,i,j,0,flag)) { return true; } } } return false; } public boolean dfs(char[][] board,char[] wordarray,int i,int j,int k,int[][] flag){ if(i>=board.length||i<0||j<0||j>=board[0].length||wordarray[k]!=board[i][j]||flag[i][j]==1) { return false; } if(k==wordarray.length-1) { return true; } flag[i][j]=1; boolean res=dfs(board,wordarray,i+1,j,k+1,flag)||dfs(board,wordarray,i,j+1,k+1,flag)||dfs(board,wordarray,i-1,j,k+1,flag)||dfs(board,wordarray,i,j-1,k+1,flag); flag[i][j]=0; return res; } }
这两段代码的区别就在于检测走过的路径方法差异,其余的思路一致
-
反省:这题之前卡住的地方在于想要先找出第一个字符在矩阵中的位置,忽略了与其后操作的统一性
2. 机器人的运动范围
-
描述:地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
-
思路:这一题和上题“矩阵中的路径”相似,不需要比较字符串,只多了一个比较数位,单独写一个计算数位的函数即可
-
题解:
class Solution { public int movingCount(int m, int n, int k) { int[][] flag=new int[m][n];//创建一个同宽高的数组记录是否到达过 return count(m,n,0,0,k,flag); } public int plus(int m,int n){//计算数位之和 int res=0; while(m!=0) { int temp=m%10; res+=temp; m=m/10; } while(n!=0) { int temp=n%10; res+=temp; n=n/10; } return res; } public int count(int m,int n,int i,int j,int k,int[][] flag){ if(i<0||j<0||i>=m||j>=n||plus(i,j)>k||flag[i][j]==1) { return 0; } flag[i][j]=1; return 1+count(m,n,i-1,j,k,flag)+count(m,n,i,j+1,k,flag)+count(m,n,i+1,j,k,flag)+count(m,n,i,j-1,k,flag); } }
-
优化:
-
数位之和计算简化:当(x+1)%10=0时,其数位之和比下一个多8,其他情况少1
用公式表示的话就是这样:(x + 1) % 10 != 0 ? s_x + 1 : s_x - 8
注:s_x表示x的数位和
-
搜索方向的简化:
图片转载自leetcode
由上图可知,只通过向右和向下移动可到达所有的可达点,机器人只需要向右移动或者向下移动
-
优化解:
class Solution { int m,n,k; int[][] flag; public int movingCount(int m, int n, int k) { this.m=m; this.n=n; this.k=k; this.flag=new int[m][n]; return dfs(0,0,0,0); } public int dfs(int i,int j,int si,int sj){ if(i>=m||j>=n||flag[i][j]==1||k<si+sj) { return 0; } flag[i][j]=1; return 1+dfs(i+1,j,(i+1)%10==0?si-8:si+1,sj)+dfs(i,j+1,si,(j+1)%10==0?sj-8:sj+1); } }
优化完搜索方向后,时间和空间的效率都优化了
-