剑指 Offer 17. 打印从1到最大的n位数(扩展:大数)【M】

剑指 Offer 17. 打印从1到最大的n位数

本文只是用来记录本人做题思路和过程,加深记忆。如果需要参考,建议参考下面的参考文章,图文并茂食用更佳。
在这里插入图片描述

本题求解很简单,不是关键,关键在于对大数的求解

1. 本题解法

由于限定死了输出的数组是int[],所以结果一定是int范围内的,而int的最大值是21亿多一点,所以最多是9位。直接设置一个辅助数组,该数组内存放1~9位数的十进制最大值。然后这个就是遍历上限:

class Solution {
    public int[] printNumbers(int n) {      // n=1~9
        int[] helper = new int[]{9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999};
        int maxValue = helper[n - 1];
        int[] res = new int[maxValue];
        for(int i = 0; i < maxValue; i++){
            res[i] = i + 1;
        }
        return res;
    }
}

2. 扩展——大数遍历

上面的解法太过于局限,所以一般会要求扩展到大数范围,即n是一个正整数,那么当n>=10后,就存在int无法表达的数字,所以需要完全切换方法:

首先明确,不管是存储的数组还是数字本身都已经不能简单的用int来表示,而统一用string来表示。

有两种方法:模拟,模拟++的过程和进位过程,但是进位效率不高,需要从最低位一位一位的判断过去。

全排列:可以发现每一位的取值都是限制在0~9,我们可以用全排列的方式求解

而全排列的解法:用回溯法:

class Solution{
    private static void dfs(StringBuilder res, StringBuilder sb, char[] num, int len){
        if(sb.length() == len){             // 递归终止条件
            res.append(sb.toString() + ",");
            return;
        }
        for(char c: num){
            sb.append(c);
            dfs(res, sb, num, len);
            sb.deleteCharAt(sb.length() - 1);
        }
    }
    public static void main(String[] args){
        int len = 9;
        char[] num = {'0','1','2','3','4','5','6','7','8','9'};
        StringBuilder res = new StringBuilder();
        dfs(res, new StringBuilder(), num, len);
        res.deleteCharAt(res.length() - 1);
        System.out.println(res.length());
    }
}

但是在实际运行的时候,n值过大,使产生的string太大会报错

但是仍存在一个问题:所有打印出来的值位数都一样,eg:00001,而实际上我们会把最高位之前的0全部去掉:

大佬解法

class Solution{
	private static int nine, start;     // nine标记的是此次dfs中出现9的次数,start标记的是最高位之前0的个数
    private static void dfs(StringBuilder res, StringBuilder sb, char[] num, int len){
        if(sb.length() == len){             // 递归终止条件
            res.append(sb.toString().substring(start) + ",");
            if(len - start == nine) start--;	// 满足了低位全为9,即0099,那说明之后是从0100开始的了,所以start要向前移(当前还不用移动)
            return;
        }
        for(char c: num){
            sb.append(c);
            if(c == '9') nine++;			// 要发生进位了,09, 下一个就是10了
            dfs(res, sb, num, len);
            sb.deleteCharAt(sb.length() - 1);
        }
        nine--;			// 回溯之后需要恢复
    }
    public static void main(String[] args){
        int len = 5;
        char[] num = {'0','1','2','3','4','5','6','7','8','9'};
        StringBuilder res = new StringBuilder();
        start = len - 1;        // 初始设置为n-1,表示除了最低位其余都是0
        dfs(res, new StringBuilder(), num, len);
        res.deleteCharAt(res.length() - 1);
        System.out.println(res);
    }
}

增加两个全局变量:nine:用来记录当前9的个数(由于是递归,所以如果一直都是9,那么会不断增加上去)

eg:len=6,

  • 前面高位为00000,固定最低位为9,此时nine=1,而此时start=5,所以从000009变成9,根据回溯的原理,下次遍历到的结点是000010,此时start更新:start=4;返回之后,nine=0;继续执行dfs
  • 此时前面高位为0000,已经固定了次低位为9,而再此基础上会进行dfs,当固定最低位为9,nine=2,此时000099,下次遍历的结点是000100,此时start更新:start:3;一次递归返回,nine=0

大佬tql

我的解法:在dfs的if里面设置一个while循环,将前面的0全部删除(如果最后全部删没了,那说明原来的值是0,补上即可)——效率不行

参考:

  1. https://leetcode-cn.com/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/solution/mian-shi-ti-17-da-yin-cong-1-dao-zui-da-de-n-wei-2/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值