剑指 Offer 13. 机器人的运动范围

地上有一个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:

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

示例 2:

  1. 输入:m = 3, n = 1, k = 0
  2. 输出:1

提示:

  • 1 <= n,m <= 100
  • 0 <= k <= 20

一、深度优先遍历DFS

根据K神思路写的代码:

  1. class Solution {
  2. public int movingCount(int m, int n, int k) {
  3. boolean[][] visited = new boolean[m][n];
  4. return dfs(visited, m, n, k, 0, 0);
  5. }
  6. private int dfs(boolean[][] visited, int m, int n, int k, int i, int j) {
  7. if(i >= m || j >= n || visited[i][j] || bitSum(i) + bitSum(j) > k) return 0;
  8. visited[i][j] = true;
  9. return 1 + dfs(visited, m, n, k, i + 1, j) + dfs(visited, m, n, k, i, j + 1) ;
  10. }
  11. private int bitSum(int n) {
  12. int sum = 0;
  13. while(n > 0) {
  14. sum += n % 10;
  15. n /= 10;
  16. }
  17. return sum;
  18. }
  19. }

注释版本:

  1. class Solution {
  2. // 棋盘的行列
  3. int m, n;
  4. // 记录位置是否被遍历过
  5. boolean[][] visited;
  6. public int movingCount(int m, int n, int k) {
  7. this.m = m;
  8. this.n = n;
  9. visited = new boolean[m][n];
  10. return dfs(0, 0, k);
  11. }
  12. private int dfs(int i, int j, int k) {
  13. // i >= m || j >= n是边界条件的判断
  14. if (i >= m || j >= n
  15. // visited[i][j]判断这个格子是否被访问过
  16. || visited[i][j] == true
  17. // k < sum(i, j)判断当前格子坐标是否满足条件
  18. || sum(i, j) > k) {
  19. return 0;
  20. }
  21. // 标注这个格子被访问过
  22. visited[i][j] = true;
  23. // 沿着当前格子的右边和下边继续访问
  24. return 1 + dfs(i + 1, j, k)
  25. + dfs(i, j + 1, k);
  26. }
  27. // 计算两个坐标数字的和
  28. private int sum(int i, int j) {
  29. int sum = 0;
  30. while (i != 0) {
  31. sum += i % 10;
  32. i /= 10;
  33. }
  34. while (j != 0) {
  35. sum += j % 10;
  36. j /= 10;
  37. }
  38. return sum;
  39. }
  40. }

k神简洁的代码:

  1. class Solution {
  2. int m, n, k;
  3. boolean[][] visited;
  4. public int movingCount(int m, int n, int k) {
  5. this.m = m; this.n = n; this.k = k;
  6. this.visited = new boolean[m][n];
  7. return dfs(0, 0, 0, 0);
  8. }
  9. public int dfs(int i, int j, int si, int sj) {
  10. if(i >= m || j >= n || k < si + sj || visited[i][j]) return 0;
  11. visited[i][j] = true;
  12. return 1 + dfs(i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj) + dfs(i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8);
  13. }
  14. }

二、广度优先遍历 BFS

  • BFS/DFS : 两者目标都是遍历整个矩阵,不同点在于搜索顺序不同。DFS 是朝一个方向走到底,再回退,以此类推;BFS 则是按照“平推”的方式向前搜索。
  • BFS 实现: 通常利用队列实现广度优先遍历。

这个代码:有点繁冗,但可以让小白看懂代码是如何运行的。

  1. class Solution {
  2. public int movingCount(int m, int n, int k) {
  3. //状态:dp[i][j]代表第i,j个格子能否走到
  4. boolean[][] dp = new boolean[m][n];
  5. dp[0][0] = isValid(0, 0, k);
  6. //转移方程
  7. for (int i = 0; i < m; i++) {
  8. for (int j = 0; j < n; j++) {
  9. if(i == 0 && j == 0) continue;
  10. else if(i == 0) dp[i][j] = isValid(i, j, k) && dp[i][j - 1];
  11. else if(j == 0) dp[i][j] = isValid(i, j, k) && dp[i - 1][j];
  12. else dp[i][j] = isValid(i, j, k) && (dp[i - 1][j] || dp[i][j - 1]);
  13. }
  14. }
  15. int count = 0;
  16. for (boolean[] row : dp) {
  17. for (boolean ele : row) {
  18. if (ele) {
  19. count++;
  20. }
  21. }
  22. }
  23. return count;
  24. }
  25. public boolean isValid(int i, int j, int k) {
  26. int sum = 0;
  27. while (i != 0) {
  28. sum += i % 10;
  29. i /= 10;
  30. }
  31. while (j != 0) {
  32. sum += j % 10;
  33. j /= 10;
  34. }
  35. return sum <= k;
  36. }
  37. }

这个代码是为了求sum又简化了代码,但跟k神比起确实还差一点。

  1. public int movingCount(int m, int n, int k) {
  2. boolean[][] nums = new boolean[m][n];
  3. nums[0][0] = isValid(0, 0, k);
  4. int sum = 1;
  5. for (int i = 0; i < m; i++) {
  6. for (int j = 0; j < n; j++) {
  7. if (i == 0 && j == 0) {
  8. continue;
  9. } else if (i == 0) {
  10. nums[i][j] = nums[i][j - 1] && isValid(i, j, k);
  11. } else if (j==0) {
  12. nums[i][j] = nums[i - 1][j] && isValid(i, j, k);
  13. } else {
  14. nums[i][j] = (nums[i - 1][j] || nums[i][j - 1]) && isValid(i, j, k);
  15. }
  16. if (nums[i][j]) sum++;
  17. }
  18. }
  19. return sum;
  20. }
  21. public boolean isValid(int m, int n, int k) {
  22. int sum = 0;
  23. while (m != 0 || n != 0) {
  24. if (m != 0) {
  25. sum += m % 10;
  26. m /= 10;
  27. }
  28. if (n != 0) {
  29. sum += n % 10;
  30. n /= 10;
  31. }
  32. }
  33. return sum <= k;
  34. }
  35. }

k神更简洁的代码:

  1. class Solution {
  2. public int movingCount(int m, int n, int k) {
  3. boolean[][] visited = new boolean[m][n];
  4. int res = 0;
  5. Queue<int[]> queue= new LinkedList<int[]>();
  6. queue.add(new int[] { 0, 0, 0, 0 });
  7. while(queue.size() > 0) {
  8. int[] x = queue.poll();
  9. int i = x[0], j = x[1], si = x[2], sj = x[3];
  10. if(i >= m || j >= n || k < si + sj || visited[i][j]) continue;
  11. visited[i][j] = true;
  12. res ++;
  13. queue.add(new int[] { i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj });
  14. queue.add(new int[] { i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8 });
  15. }
  16. return res;
  17. }
  18. }

参考链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof/solution/mian-shi-ti-13-ji-qi-ren-de-yun-dong-fan-wei-dfs-b/

剑指 Offer 13. 机器人的运动范围的更多相关文章

  1. 剑指 Offer 13. 机器人的运动范围 + 深搜 + 递归

    剑指 Offer 13. 机器人的运动范围 题目链接 package com.walegarrett.offer; /** * @Author WaleGarrett * @Date 2020/12/ ...

  2. 【Java】 剑指offer(12) 机器人的运动范围

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 地上有一个m行n列的方格.一个机器人从坐标(0, 0)的格子开始移 ...

  3. Go语言实现:【剑指offer】机器人的运动范围

    该题目来源于牛客网<剑指offer>专题. 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之 ...

  4. 剑指Offer 66. 机器人的运动范围 (回溯)

    题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能 ...

  5. [剑指Offer] 66.机器人的运动范围

    题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能 ...

  6. 剑指offer:机器人的运动范围(回溯法DFS)

    题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能 ...

  7. 剑指offer——14机器人的运动范围

    题目描述 地上有一个m行和n列的方格.一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子. 例如,当k为18时,机器人能 ...

  8. 剑指offer(13)-栈的压入、弹出序列 九度1366

    题目来自剑指offer系列 九度 1366:http://ac.jobdu.com/problem.php?pid=1367 题目描述: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列 ...

  9. 【Java】 剑指offer(13) 剪绳子

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 给你一根长度为n绳子,请把绳子剪成m段(m.n都是整数,n> ...

随机推荐

  1. 深入理解Java并发容器——ConcurrentHashMap

    目录 重要属性和类 put 为什么java8后放弃分段锁,改用CAS和同步锁 初始化 addCount 扩容 树化 参考 重要属性和类 sizeCtl 容量控制标识符,在不同的地方有不同用途,而且它的 ...

  2. CVE-2017-12615 Tomcat远程代码执行

    影响版本: Apache Tomcat 7.0.0 - 7.0.81 ps:安装Tomcat需要安装jdk(JAVA环境) 下面来正经复现,Payload: 利用burpsuite 进行抓包 发送到r ...

  3. Selenium启动Firefox示例(java版)

    本文示例使用selenium启动Firefox,并将浏览器窗口最大化,在百度搜索框内输入"HelloWorld",最后点击搜索按钮. 源代码如下: 1 package com.se ...

  4. 实验 2 Scala 编程初级实践

    实验 2 Scala 编程初级实践 一.实验目的 1.掌握 Scala 语言的基本语法.数据结构和控制结构: 2.掌握面向对象编程的基础知识,能够编写自定义类和特质: 3.掌握函数式编程的基础知识,能 ...

  5. shell脚本(3)-格式化输出

    一个程序需要有0个或以上的输入,一个或更多输出 一.echo语法 1.功能:将内容输出到默认显示设备. echo命令功能在显示器上显示一段文字,一般提到提示的作用 2.语法:echo[-ne][字符串 ...

  6. 每天五分钟Go - 函数基础

    函数在定义 Go的函数使用func来定义,返回类型支持多个值的返回 func 函数名([参数列]) [返回值类型]{ 方法执行体 } 参数列支持多个参数的声明,同一类型的函数,声明时和变量的声明一样 ...

  7. 微信小程序账号注册

    想要开发微信小程序,先注册账号申请APPID. 第一步:百度搜索"微信公众平台" 第二步:立即注册 进入注册页面 区别: 订阅号: 订阅号在文件夹里,订阅号消息 一天只能推送一次, ...

  8. 第四篇--Beyond Compare4 试用期30天后

    30天后删除BCUnrar.dll这个文件,继续使用30天.还有就是注册表中regedit-->HEKY_CURRENT_USER-->Software-->Scooter Soft ...

  9. netcore一键nssm发布为windows服务

    AntDeploy 是我开发一款开源一键部署工具包 发布功能支持: docker容器一键部署 docker镜像一键发布 支持iis一键部署 windows服务一键部署 linux服务一键部署 支持增量 ...

  10. C++ 定义默认值void locals_index(int reg, int offset = 1);

    看jvm源码的时候怎么也看不懂,来回看了几次了就是关于iload 6 指令的解析 def(Bytecodes::_lload , ubcp|____|____|____, vtos, ltos, ll ...