java剑指offer机器人_剑指offer机器人运动范围 JZ66

目录

本文是参考牛客网的官方题解结合自己理解写的,官方题解:牛客官方题解

其中官方题解采用C++,博主已入JAVA坑,理解官方题解意思,使用JAVA写的

题目描述

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

题目理解

给定一个矩阵的行和列row,columns和阈值threshold,从(0,0)出发,每次可以往上下左右四个方向走,并且走到(i,j)时,i和j的每位数之和需要小于等于threshold,问最多可以走多少格子。

对于这种遍历,我们首先可以想到深度优先搜索(DFS)或者广度优先搜索(BFS),当满足条件的进行标记,依次遍历完所有节点

方法一:DFS遍历

根据题目描述,我们可以模拟题目,我们假设一个5x5矩阵,阈值threshold=3,如果我们用DFS的话,就是按照某一个分支进行访问,而这种分支访问一般是采用递归的方式进行实现,对于DFS大家最好先理解递归,可以先看我上一篇剪绳子的题,就是一个很典型的递归.我在下面画了一个图,按照对应的方向进行搜索.

8b4e8c06dddb8ba38990b0d96d37cbda.png

最开始,我们在(0,0)的位置,我们假设按照{右,上,左,下}的方向去试探。所以我们走的顺序应该是按照图中的下标走的。

当走到4的时候,发现不能往继续往右边走,并且4个方向都走不通了,那就回溯到3,发现可以走到5,接着就站在5的视角,发现可以走6,就一直按照这个想法。

本题的递归函数就是:首先站在(0,0)的视角,先往右试探,发现可以走,就以下一个为视角,继续做相同的事情

package JZ66_Robot_move;

import java.util.Scanner;

import java.util.Arrays;

/*

* DFS深度优先,Depth First Search 对每一个可能的分之路径深入到不能深入为止

* 且每个节点只能访问一次,同时做相应标记,当访问到该分支路径的末尾节点,就回溯到上一个节点,站在这个节点再进行四个方向的探索

* 假设有一个5*5的矩阵,我们用DFS,就是一直按照一个方向走,假设我们按照{右,上,左,下}的方向试探,

* 就是先按照向右一直搜索,当位置大于阈值就回溯到前面的位置在向下一直搜索

* 第一步,检查下标

* 第二步:检查是否被访问过,或者是否满足当前匹配条件

* 第三步:检查是否满足返回结果条件

* 第四步:都没有返回,说明应该进行下一步递归

* 标记

* dfs(下一次)

* 回溯

*/

public class Dfs_Move {

/*四个方向

* x+dir[i+1] y+dir[i]

* x+0 y+1 右

* x-1 y+0 上

* x+0 y-1 左

* x+1 y+0 下

* 想把右,下,左,上排列出来,但是尝试了下,会出现重复

*/

public int[] dir= {1, 0 ,-1 ,0 ,1};

public static int count=0;

//下表转化 如35转成5+3=8

public int check(int n) {

int sum=0;

while(n>0) {

sum+=(n%10);

n/=10;

}

return n;

}

public void dfs(int x,int y,int threshold,int rows,int columns,int[][] mark) {

//检查下标

if(x<0||x>=rows||y<0||y>=columns) {

return ;

}

//必须分开,不然数组越界会报错

if(mark[x][y]==1) {

return ;

}

int sum_xy=check(x)+check(y);

//检查坐标之和是否大于阈值

if(sum_xy>threshold) {

return ;

}

//此时经过检查 坐标[x] [y]是满足条件的

mark[x][y]=1;

count+=1;

//进行下一步的递归,按照右下左上的方向试探

for(int i=0;i<4;i++) {

dfs(x+dir[i+1],y+dir[i],threshold,rows,columns,mark);

}

}

public static void main(String[] args) {

System.out.print("Enter a row:");

Scanner sc=new Scanner(System.in);

int rows=sc.nextInt();

System.out.println("Enter a columns:");

int columns=sc.nextInt();

System.out.println("Enter a threshold:");

int threshold=sc.nextInt();

int[][] mark=new int[rows][columns];

for(int i=0;i

for(int j=0;j

mark[i][j]=0;

}

}

Dfs_Move a=new Dfs_Move();

a.dfs(0,0,threshold,rows,columns,mark);

System.out.println(count);

}

}

时间复杂度:O(mn), m,n为矩阵大小,每个元素最多访问过一次

空间复杂度:O(mn)

方法二:BFS遍历

当前图的遍历算法还有广度优先搜索(BFS),所以也可以用BFS做。方法一实例的图,用BFS就是如下这样:

a8a65ccdf90cba015f30e7a7b3f85f31.png

广度优先

1.顶点v入队列

2.当队列非空时则继续执行,否则算法结束

3.出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。

4.查找顶点v的一个邻接顶点close

5.若colse未被访问过的,则colse入队列。

6.继续查找顶点v的另一个新的邻接顶点new_col,转到步骤(5)。直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)

package JZ66_Robot_move;

import java.util.*;

/*广度优先

* 1.顶点v入队列

* 2.当队列非空时则继续执行,否则算法结束

* 3.出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。

* 4.查找顶点v的一个邻接顶点close

* 5.若colse未被访问过的,则colse入队列。

* 6.继续查找顶点v的另一个新的邻接顶点new_col,转到步骤(5)。直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。

*/

//创建一个类似C++中的Pair结构,用于存放下标x,y

class Pair {

private int meb_x;

private int meb_y;

public Pair(int x,int y) {

this.meb_x=x;

this.meb_y=y;

}

public int getX() {

return meb_x;

}

public int getY() {

return meb_y;

}

}

public class Bfs_Move {

private final int[] dir={1, 0, -1 , 0, 1};

//下标转换

public int check(int n) {

int sum=0;

while(n>0) {

sum+=(n%10);

n/=10;

}

return sum;

}

public static void main(String[] args) {

System.out.print("Enter a row:");

Scanner sc=new Scanner(System.in);

int rows=sc.nextInt();

System.out.println("Enter a columns:");

int columns=sc.nextInt();

System.out.println("Enter a threshold:");

int threshold=sc.nextInt();

int[][] mark=new int[rows][columns];

for(int i=0;i

for(int j=0;j

mark[i][j]=0;

}

}

int count=0;

Bfs_Move bfs=new Bfs_Move();

//创建一个队列,根据它的先进先出的特性,我们可以把顶点v中的所有近邻节点先存入,

//然后一层一层按照先后顺序添加进队列中,实现广度遍历

Queue q=new LinkedList();

q.add(new Pair(0,0));

mark[0][0]=1;

count++;

//只要队列一直不为空,就不结束循环

while(!q.isEmpty()) {

//poll()会返回队列第一个元素,同时删除这个元素

Pair p=q.poll();

//注意和DFS中的区别,DFS利用此循环进行递归,会一直先按照一个方向,比如此时的右,当访问到最后节点就回溯到之前按照其他方向一次探索

//在BFS中则是按照节点周围一圈先添加,在添加外面节点周围一圈

for(int i=0;i<4;i++) {

int x=p.getX()+bfs.dir[i+1];

int y=p.getY()+bfs.dir[i];

//可以观察 广度优先的遍历顺序

System.out.println("x y:"+x+" "+y);

int sum_xy=bfs.check(x)+bfs.check(y);

if(x>=0&&x=0&&y

count++;

mark[x][y]=1;

q.add(new Pair(x,y));

}

}

}

System.out.println(count);

}

}

本文地址:https://blog.csdn.net/weixin_43568893/article/details/107877710

希望与广大网友互动??

点此进行留言吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值