66.机器人的运动范围
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
典型的DFS (深度优先搜索)|| BFS(宽度/广度优先搜索)题
DFS-Depth-first search适用搜索全部的解
主要的特性是深度优先,总是不停的往下找,走到没路才罢休。
BFS-Breadth-First-Search适用搜索最短路径的解
主要特性则是从root开始扩展,每一层都是精密的搜索完整了才下一个。
所谓深度优先搜索,是从图中的一个顶点出发,每次遍历当前访问顶点的临界点,一直到访问的顶点没有未被访问过的临界点为止。然后采用依次回退的方式,查看来的路上每一个顶点是否有其它未被访问的临界点。访问完成后,判断图中的顶点是否已经全部遍历完成,如果没有,以未访问的顶点为起始点,重复上述过程。深度优先搜索是一个不断回溯的过程。
所谓广度优先搜索,类似于树的层次遍历。从图中的某一顶点出发,遍历每一个顶点时,依次遍历其所有的邻接点,然后再从这些邻接点出发,同样依次访问它们的邻接点。按照此过程,直到图中所有被访问过的顶点的邻接点都被访问到,最后还需要做的操作就是查看图中是否存在尚未被访问的顶点,若有,则以该顶点为起始点,重复上述遍历的过程。
本题用DFS来解题,提供递归和非递归两种方法:
方法1:递归
递归的方式更加简单了,比上一题简单
出口:
1:a.不满足边界条件 ;b.已经遍历过;c.位数和大于阈值
2.递:a.标记遍历 b.上下左右递归
3.归:返回count
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
if(rows<=0||cols<=0||threshold<0) return 0;
boolean[][] visited=new boolean[rows][cols];
return dfs(threshold,rows,cols,visited,0,0); //dfs深度优先遍历,从0,0下标开始
}
private int dfs(int threshold,int rows,int cols,boolean[][] visited,int x,int y){
//是否满足条件
if(x<0||x>=rows||y<0||y>=cols
||getSum(x)+getSum(y)>threshold
|| visited[x][y])
return 0;
visited[x][y]=true;//标记已经访问
return 1+dfs(threshold,rows,cols,visited,x,y-1)//四个方向遍历下
+dfs(threshold,rows,cols,visited,x+1,y)/右
+dfs(threshold,rows,cols,visited,x,y+1)//上
+dfs(threshold,rows,cols,visited,x-1,y); //左
}
private int getSum(int i){//计算各个位数之和如35=3+5
int sum=0;
while(i>0){
sum+=i%10;
i/=10;
}
return sum;
}
}
方法一:非递归
思路:不带记忆的DFS搜索 + 限定条件 = 普通的DSF例题
1.需要记录已经遍历过的节点,用辅助矩阵visited[rows * cols]
2.每次加入栈时,count++,标记已经遍历,这样下一个节点就不会遍历了
入栈条件:
1.每一位的和小于等于threshold:
2.x和 y 的边界条件
3.没有遍历过
下面代码有问题:
import java.util.Stack;
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
if(rows<=0||cols<=0||threshold<0) return 0;
Stack<Integer> s=new Stack<>();
boolean[][] visited=new boolean[rows][cols];
int[][] xoy={{0,1,0,-1},{1,0,-1,0}};//四个方向
int count=0;
s.add(0);
visited[0][]=true;
while(!s.isEmpty()){
int cur=s.pop();
count++;
for(int i=0;i<4;i++){
int x=cur%cols+xoy[0][i];
int y=cur/cols+xoy[1][i];
int sum=getSum(x)+getSum(y);
if(x>=0&&x<rows&&y>=0&&y<cols&&sum<=threshold&&!visited[x][y]){
s.add(x+y*cols);
visited[x][y]=true;
}
}
}
return count;
}
private int getSum(int i){//计算各个位数之和如35=3+5
int sum=0;
while(i>0){
sum+=i%10;
i/=10;
}
return sum;
}
}