机器人的运动范围(剑指offer 13) Java深度优先遍历

简介: 地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。

一、题目描述



       地上有一个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。请问该机器人能够到达多少个格子?


示例 1:

输入:m = 2, n = 3, k = 1

输出:3


示例 2:

输入:m = 3, n = 1, k = 0

输出:1


提示:

1 <= n,m <= 100

0 <= k <= 20


二、思路讲解


       

对于我这种算法小白来说,看见在矩阵中上下左右跑的,直接无脑深搜。


从(0,0)开始,像上下左右方向分别找满足条件的节点,如果某一个方向满足条件,就走到这个位置,继续找这个位置的上下左右(递归);如果某一个方向不满足条件,应该排除掉这个方向(剪枝操作)。当四个方向都找完之后,回到上一个节点(回溯)。


为了避免走“回头路”,避免将已经访问过的节点再算上去,我们定义一个二位数组visited,来标记是否访问过。


然后是确定跳出递归的条件:


1、超出边界;


2、数位之和大于k;


3、已经被访问过。


三、Java代码实现



class Solution {
    public int movingCount(int m, int n, int k) {
        //用来标记该位置是否访问过 为1则访问过
        int [][]visited = new int[m][n];
        return dfs(0, 0, m, n, k, 0, visited);
    }
    public static int dfs(int i, int j, int m, int n, int k, int count, int [][]visited) {
        //如果指针越界 或 行列数位之和大于k 或 被访问过,则直接返回count次数
      if(i<0 || j<0 || i>=m || j>=n || fun(i, j)>k || visited[i][j]==1) {
        return count;
      }
        //将当前位置标记为已访问
      visited[i][j] = 1;
        //满足条件的格子数+1
      count++;
      count = dfs(i-1, j, m, n, k, count, visited); //往上找
      count = dfs(i+1, j, m, n, k, count, visited); //往下找
      count = dfs(i, j-1, m, n, k, count, visited); //往左找
      count = dfs(i, j+1, m, n, k, count, visited); //往右找
      return count;
    }
    //用来计算坐标为(m,n)的数位之和
    public static int fun(int m, int n){
        int sum = 0;
        while(m!=0){
            sum = sum + m%10;
            m = m/10;
        }
        while(n!=0){
            sum = sum + n%10;
            n = n/10;
        }
        return sum;
    }
}


四、时空复杂度分析



时间复杂度:        O(MN)        最坏情况下,机器人遍历整个矩阵


空间复杂度:        O(MN)        最坏情况下,visited矩阵存储所有单元格的索引


五、代码优化



1、不需要向上和向左搜索

     

由于机器人从左上角出发,所以他只会往右或往下走,因此不需要向上和向左搜索。


2、 数位求和无需循环


由于题目中矩阵的坐标都是一位或者两位数,要想求这样数字的数位和只需要x%10 + x/10即可 。


3、函数传值还可简化


其实dfs中不需要把count传进去计算所有满足条件的格子数量,只需要返回这一支的满足条件的数量就行了。

class Solution {
    public int movingCount(int m, int n, int k) {
        //用来标记该位置是否访问过 为1则访问过
        int [][]visited = new int[m][n];
        return dfs(0, 0, m, n, k, visited);
    }
    public static int dfs(int i, int j, int m, int n, int k, int [][]visited) {
        //如果指针越界 或 行列数位之和大于k 或 被访问过,则直接返回count次数
      if(i<0 || j<0 || i>=m || j>=n || fun(i, j)>k || visited[i][j]==1) {
        return 0;
      }
        //将当前位置标记为已访问
      visited[i][j] = 1;
        //         往下找                          往右找           
      return 1 + dfs(i+1, j, m, n, k, visited) + dfs(i, j+1, m, n, k, visited);
    }
    //用来计算坐标为(m,n)的数位之和
    public static int fun(int m, int n){
        return m%10 + m/10 + n%10 + n/10;
    }
}


相关文章
|
4月前
|
存储 Java
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
|
1月前
|
存储 Java 开发者
在 Java 中,如何遍历一个 Set 集合?
【10月更文挑战第30天】开发者可以根据具体的需求和代码风格选择合适的遍历方式。增强for循环简洁直观,适用于大多数简单的遍历场景;迭代器则更加灵活,可在遍历过程中进行更多复杂的操作;而Lambda表达式和`forEach`方法则提供了一种更简洁的函数式编程风格的遍历方式。
|
2月前
|
Java 程序员 编译器
Java|如何正确地在遍历 List 时删除元素
从源码分析如何正确地在遍历 List 时删除元素。为什么有的写法会导致异常,而另一些不会。
36 3
|
2月前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
25 1
|
2月前
|
存储 算法 Java
Java一分钟之-数组的创建与遍历
数组作为Java中存储和操作一组相同类型数据的基本结构,其创建和遍历是编程基础中的基础。通过不同的创建方式,可以根据实际需求灵活地初始化数组。而选择合适的遍历方法,则可以提高代码的可读性和效率。掌握这些基本技能,对于深入学习Java乃至其他编程语言的数据结构和算法都是至关重要的。
30 6
|
3月前
|
域名解析 分布式计算 网络协议
java遍历hdfs路径信息,报错EOFException
java遍历hdfs路径信息,报错EOFException
40 3
|
4月前
|
数据可视化 机器人 Python
实例9:四足机器人运动学正解平面RR单腿可视化
本文是关于四足机器人正向运动学(FK)的实例教程,通过Python编程实现了简化的mini pupper平面二连杆模型的腿部可视化,并根据用户输入的关节角计算出每个关节相对于基坐标系的坐标。
79 1
|
4月前
|
数据可视化 算法 机器人
实例10:四足机器人运动学逆解可视化与实践
本文是关于四足机器人逆运动学(IK)的实例教程,介绍了逆运动学的概念、求解方法、多解情况和工作空间,并通过Python编程实现了简化的mini pupper平面二连杆模型的逆运动学可视化,包括单腿舵机的校准和动态可视化运动学计算结果。
220 0
|
3天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
26 6
|
18天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####