剑指offer-test66

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;
	 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值