【算法】解题总结:剑指Offer 13 机器人的运动范围、剑指Offer 17 打印从1到最大的n位数

JZ13 机器人的运动范围

(较难)

题目

描述
在这里插入图片描述

示例1
输入:
1,2,3
返回值:
3

示例2
输入:
0,1,3
返回值:
1

示例3
输入:
10,1,100
返回值:
29
说明:
[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[0,10],[0,11],[0,12],[0,13],[0,14],[0,15],[0,16],[0,17],[0,18],[0,19],[0,20],[0,21],[0,22],[0,23],[0,24],[0,25],[0,26],[0,27],[0,28] 这29种,后面的[0,29],[0,30]以及[0,31]等等是无法到达的

示例4
输入:
5,10,10
返回值:
21

思路1:DFS

本文题意为从 [0,0] 开始遍历到[rows-1, cols-1],遇到数位和大于给定的 threshold 值的坐标位置就相当于死路,也可理解为像是边界一样的墙,此题虽说是可以向上下左右四个方向走,但是其实只要向右或者下走就可以了,这点需要意会,而此题解法又是属于一种很明显的深度优先遍历思想,因此递归的终止条件就可以是遇到内部墙或是超出边界墙,就返回 0,之所以返回 0,是因为本题要求计数可以到达的坐标总个数,因为当前遇到内部墙,因此此坐标的这种情况自然就不应被计数进去,而对于当前坐标没有遇到内部墙,又没有超出边界墙,这时可以返回其子情况的计数结果 + 1,1 表示的是当前坐标的这种情况。

注意:必须要加一个记录是否 [row, col] 坐标被访问过的标识数组,例如 boolean[][] visited 数组,因为其递归的子情况,下递归、右递归可能出现重复计数过同一坐标的情况,因此要进行标识,这也是进行深度优先遍历务必要考虑的一件事。

实现

public class JZ13机器人的运动范围 {

    int threshold = 0;
    int rows = 0;
    int cols = 0;
    boolean[][] visited = null;

    public int movingCount(int threshold, int rows, int cols) {
        this.threshold = threshold;
        this.rows = rows;
        this.cols = cols;
        this.visited = new boolean[rows][cols];
        return moving(0, 0);
    }

    public int moving(int row, int col) {
        //返回:位数不符合、边界、访问过
        if (digitSum(row, col) > threshold
                || row >= rows || col >= cols
                || visited[row][col]) return 0;

        //标注这个格子被访问过
        visited[row][col] = true;

        //子情况 + 当前情况的1次
        return moving(row + 1, col) + moving(row, col + 1) + 1;
    }

    public int digitSum(int num1, int num2) {
        int sum = 0;
        String total = "" + num1 + num2;
        char[] digits = total.toCharArray();
        for (char digit : digits) {
            sum += Integer.parseInt(digit + "");
        }
        return sum;
    }
}

在这里插入图片描述

思路2:BFS

BFS 的思想也十分基础, 借助一个队列实现,之前文章讲解过 BFS 的思路(Java实现【邻接矩阵、邻接表的创建、遍历(DFS,BFS)】+图解+完整代码,当时是用图结构来写的,而这里无非就是向下向右两条路线,可理解为出度为 2 的图),这里不再赘述。

实现

public class Test {
    public int movingCount(int threshold, int rows, int cols) {
        boolean[][] visited = new boolean[rows][cols];
        int count = 0;
        Queue<int[]> queue = new LinkedList<>();

        queue.add(new int[]{0, 0});
        while (queue.size() > 0) {
            int[] next = queue.poll();
            int row = next[0], col = next[1];
            //返回:位数不符合、边界、访问过
            if (row >= rows || col >= cols || threshold < digitSum(row, col) || visited[row][col])
                continue;
            //标注这个格子被访问过
            visited[row][col] = true;
            count++;
            //下边坐标
            queue.add(new int[]{row + 1, col});
            //右边坐标
            queue.add(new int[]{row, col + 1});
        }
        return count;
    }

    public int digitSum(int num1, int num2) {
        int sum = 0;
        String total = "" + num1 + num2;
        char[] digits = total.toCharArray();
        for (char digit : digits) {
            sum += Integer.parseInt(digit + "");
        }
        return sum;
    }
}

在这里插入图片描述

JZ17 打印从1到最大的n位数

(简单)

题目

描述
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。
1、用返回一个整数列表来代替打印
2、n 为正整数

示例
输入:
1
返回值:
[1,2,3,4,5,6,7,8,9]

思路

此题用 Java 语言实现起来十分容易,将读入的 n 位数生成 n 个 9,组成一个数,那么这个数就是当前 n 位数中最大的,那么我们返回 1 到这个数的数组即可。

实现

public class JZ17打印从1到最大的n位数 {
    public int[] printNumbers (int n) {
        int digit = Integer.parseInt(n + "");
        String maxString = "";
        for (int i = 0; i < digit; i++) {
            maxString += "9";
        }
        int max = Integer.parseInt(maxString);
        int[] res = new int[max];
        for (int i = 0; i < res.length; i++) {
            res[i] = i + 1;
        }
        return res;
    }
}

在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超周到的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值