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

  • 题目描述

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

示例 1:

输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
 

说明:

用返回一个整数列表来代替打印
n 为正整数

  • 分析

简单做法这里就不记录了,虽然在python里面不考虑大数越界问题,但是面试的时候要是就仅仅手写个for循环+append,肯定offer就凉了。

参照题解: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/

因此,可以考虑将打印数的问题转化为打印string的全排列问题,可以看这个图理解排列过程:

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

 

 就是从n位到各位逐渐求0~9的排列组合。因此可以用递归实现,递归的思想是:

向低位递归,当个位已经被固定时,添加数字的字符串,例如n=2时,固定十位0~9,递归最小规模为当递归到个位数时,添加数字字符串。

但是,仅仅这样输出的是元素为string的list,并且存在01 02 010 099 这样的前面带0的数,因此我们还需要去前面的0才是最终的打印出来正常的数字。

(这里其实我就理解得不是很透彻了)

删除高位数字:

1.字符串左边界定义:设定start为左边界,用nums[start:]控制输出的不为零的数

2.左边界start的变化规律:观察可知,当输出数字的所有位都是 99 时,则下个数字需要向更高位进 11 ,此时左边界 startstart 需要减 11 (即高位多余的 00 减少一个)。例如当 n = 3n=3 (数字范围 1 - 9991−999 )时,左边界 start 需要减 1的情况有: "009" 进位至 "010" , "099" 进位至 "100" 。设数字各位中 99 的数量为 nine,所有位都为 99的判断条件可用以下公式表示:

n−start=nine

3.统计nine的方法:固定第x位,当i=9,则nine=nine+1,并且一定要在回溯前回复nine=nine-1

代码

 

class Solution:
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n:  # 终止条件:已固定完所有位
                s = ''.join(num[self.start:])
                #res.append(''.join(num))  # 拼接 num 并添加至 res 尾部
                if s != '0':
                    res.append(int(s))
                if n - self.start == self.nine:
                    self.start -= 1
                return
            for i in range(10):  # 遍历 0 - 9
                if i == 9:
                    self.nine += 1
                num[x] = str(i)  # 固定第 x 位为 i
                dfs(x + 1)  # 开启固定第 x + 1 位
            self.nine -= 1

        num = ['0'] * n  # 起始数字定义为 n 个 0 组成的字符列表
        res = [] # 数字字符串列表
        self.nine = 0
        self.start = n -1
        dfs(0)  # 开启全排列递归
        return res

 

上一篇:[Java学习笔记]不规则数组的学习:九九乘法表


下一篇:0423. Reconstruct Original Digits from English (M)