剑指offer(第二版)——打印从1到最大的n位数

该博客分享了如何使用Java实现《剑指offer》中的一道算法题,即根据输入的数字n打印出1到最大的n位十进制数。文中提供了两种解法,一种是使用字符串模拟数字加法,另一种是递归求解全排列。博客还包含了测试用例和代码实现,并鼓励读者交流和探讨解题思路。
摘要由CSDN通过智能技术生成

PS:《剑指offer》是很多同学找工作都会参考的一本面试指南,同时也是一本算法指南(为什么它这么受欢迎,主要应该是其提供了一个循序渐进的优化解法,这点我觉得十分友好)。现在很多互联网的算法面试题基本上可以在这里找到影子,为了以后方便参考与回顾,现将书中例题用Java实现(第二版),欢迎各位同学一起交流进步。

GitHub: https://github.com/Uplpw/SwordOffer

完整题目链接: https://blog.csdn.net/qq_41866626/article/details/120415258

1 题目描述

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

leetcode链接: 打印从1到最大的n位数(以下代码已测试,提交通过)

2 测试用例

一般是考虑功能用例,特殊(边缘)用例或者是反例,无效测试用例这三种情况。甚至可以从测试用例寻找一些规律解决问题,同时也可以让我们的程序更加完整鲁棒。

(1)功能用例:正常的n值,如1,2。

(2)边缘用例:n值较大使得 int、long类型无法存储数据,如100。

(3)无效用例:n为0,负数。

3 思路

分析:

此题没有说不需要考虑大数问题,所以是需要考虑的。这样就不能直接用常规的方法来做。

下面是两种思路的具体过程。

解法1:使用字符串模拟数字的加法

一般大数问题都可以转换为字符串的操作。

  • 计算位数为n的整数个数k,并创建大小位k字符数组。
  • 做循环加法,当没有计算到最后一个数字,返回true,此时记录当前字符数组情况,否则返回false。
  • 最后返回字符数组的所有记录即可。

解法2:递归求解(n位数字的全排列)

  • 从最高位开始,循环逐步加1(直到9),然后开始递归低位。
  • 当递归到最低位,返回输出当前值。

4 代码

算法实现:

public class Print1ToMaxOfNDigits {
    // 解法1:使用字符串模拟数字的加法
    public static int[] printNumbers(int n) {
        if (n <= 0) {
            return new int[0];
        }
        // 计算位数为n的整数个数
        int length = 0;
        for (int i = 1; i <= n; i++) {
            length = length * 10 + 9;
        }
        char[] array = new char[n];
        for (int i = 0; i < n; i++) {
            array[i] = '0';
        }
		// 记录字符数组情况
        int[] temp = new int[length];
        int index = 0;
        while (increase(array)) {
            temp[index++] = print(array);
        }
        return temp;
    }

    // 模拟加法
    public static boolean increase(char[] array) {
        for (int i = array.length - 1; i >= 0; i--) {
            // 字符不是9,字符加1
            if (array[i] < '9' && array[i] >= '0') {
                array[i] = (char) ((int) array[i] + 1);
                return true;
            // 字符是9 当前字符改为0,进入下次for循环
            } else if (array[i] == '9') {
                array[i] = '0';
            } else {
                return false; // 无效字符
            }
        }
        // 最高位加法完成,循环结束
        return false;
    }

	// 解法1与解法2共用:返回字符数组代表的数字
	public static int print(char[] array) {
        int count = 0;
        for (int i = 0; i < array.length; i++) {
            count = count * 10 + (int) (array[i] - '0');
        }
        return count;
    }

    // 解法2:递归解法
    public static int[] printNumbersRecursionly(int n) {
        if (n <= 0) {
            return new int[0];
        }
        char[] array = new char[n];
        for (int i = 0; i < n; i++) {
            array[i] = '0';
        }
        // 记录字符数组情况
        int length = 0;
        for (int i = 1; i <= n; i++) {
            length = length * 10 + 9;
        }
        int[] result = new int[length];
        List<Integer> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            // 最高位逐步加1,然后递归低位
            array[0] = (char) ('0' + i);
            printNumbersCoreRecursionly(array, n, 0, list);
        }
        for (int i = 0; i < list.size(); i++) {
            result[i] = list.get(i);
        }
        return result;
    }


    public static void printNumbersCoreRecursionly(char[] array, int n, int index, List<Integer> list) {
        // 递归到最低位 开始打印
        if (index == n - 1) {
            int current = print(array);
            if (current != 0) {
                list.add(current);
            }
            return;
        }
        for (int i = 0; i < 10; i++) {
            // 当前位逐步加1,再次递归低位
            array[index + 1] = (char) ('0' + i);
            printNumbersCoreRecursionly(array, n, index + 1, list);
        }
    }

    public static void main(String[] args) {
        printNumbers(2);
        printNumbersRecursionly(2);
    }
}


参考
在解决本书例题时,参考了一些大佬的题解,比如leetcode上的官方、K神,以及其他的博客,在之后的每个例题详解后都会给出参考的思路或者代码链接,同学们都可以点进去看看!

本例题参考:
https://www.jianshu.com/p/71c20c0a44b5

本文如有什么不足或不对的地方,欢迎大家批评指正,最后希望能和大家一起交流进步、拿到心仪的 offer !!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值