剑指 offer 17 打印从1到最大的n位数(主要是为了解决大数问题)

1. 题目描述

2. 算法思路

这个题,如果只是解决题目的话,就很简单,真正难的是大数问题,由于大数问题的存在,就必须使用到字符串来处理,这里先给出一个可以ac的代码。

class Solution {
    public int[] printNumbers(int n) {
        int end = (int)Math.pow(10,n) - 1;  //求出最大的数
        int[] res = new int[end];
        for(int i = 0; i < end; i++){
            res[i] = i + 1;
        }
        return res;
    }
}

2.1 提交结果 

 3. 大数打印的解法

大数打印面临下述三个问题:

  1. 大数的变量类型表示
  2. 如何生成数字的集合/字符串集
  3. 使用递归生成全排列,对于001这种数前面0的处理

对于上述问题的解决思路:建议结合代码观看

  1. 变量类型使用string
  2. 既然是字符串,我们就可以不用考虑进位。因为最终答案是0 - 9的全排列,因此可以递归生成数字的string列表
  3. 先固定高位,向低位递归。为了解决0的问题,定义一个left(字符串的左边界)和一个数组中9的个数nine,
    1. 例如n = 2时, 1 - 9 时 start = 1, 10 - 99 时 start = 0 。
    2. 当前数字全是9时,例如( 0099 ) ,就代表left要左移一位了。
    3. 判断当前数字全为9
      1. 每当遍历到一个9,nine++;
      2. 在终止条件中进行判断, n - left == nine ;就代表发生进位,left左移,同时 nine--;

 

3.1 代码(这个代码并不能ac,因为返回的是字符串,稍微改变即可)

class Solution {

    StringBuilder res = new StringBuilder();
    int n;
    int nine = 0;
    int left;
    char[] num, loop = {'0','1','2','3','4','5','6','7','8','9'};
    public int[] printNumbers(int n) {
        this.n = n;
        num = new char[n]; //长度和n一样的字符数组
        left = n - 1;
        dfs(0);
        res.deleteCharAt(res.length() - 1); //删除最后的逗号
        return res.toString();
    }

    void dfs(int x){
        if(x == n){ //代表固定完了所有位
            //拼接num,并添加到res
            String s =  String.valueOf(num).substring(left));    //只取left右边的,因为左边全是0
            if(!s.equals("0")) //因为是从1开始的,所以排除0
                res.append(s + ",");
            if(n - left == nine)    //当出现例如 0099,left左移
                left--;
            return;
        }
        for(char i : loop){ //遍历 '0' - '9'
            if(i == '9')
                nine++;
            num[x] = i; //固定第x位为i
            dfs(x + 1); //开始固定下一位
        }
        //回溯前,nine减一,因为到这一步的时候,已经实现了000-009,发生了进位,并且left已经左移,因此需要讲此前的nine还原。
        nine--;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值