桂桂卷的刷题日常-剑指offer17递归图示

Posted by CYY on May 29, 2021

努力刷题的钢铁桂桂卷(๑•̀ㅂ•́)و✧

大数打印题目描述

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

示例 1:

输入: n = 1

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

桂桂卷的率真解法

刚开始为秋招准备,这些题一看就只会暴力解除:

1
2
3
class Solution:
    def printNumbers(self, n: int) -> List[int]:
        return [i+1 for i in range(0, 10**n-1)]

(时间复杂度O(10n),空间复杂读度O(1))。虽然提交通过,但是面试的时候肯定不是考这种解题思路的( -‘`-; )

大神们的厉害解法

大神们总是能考虑得更多一些,比如这道大数打印题就需要考虑大数越界问题啦。

厉害得解法之一呢,就是使用字符串表示数字,并使用递归的思想。下面是大神的递归写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution:
    def printNumbers(self, n: int) -> [int]:
        def dfs(x):
            if x == n:
                s = ''.join(num[self.start:])
                if s != '0': res.append(int(s))
                if n - self.start == self.nine: self.start -= 1
                return
            for i in range(10):
                if i == 9: self.nine += 1
                num[x] = str(i)
                dfs(x + 1)
            self.nine -= 1
        
        num, res = ['0'] * n, []
        self.nine = 0
        self.start = n - 1
        dfs(0)
        return res

具体的解题思路大家可以移步这里

写这份博客的目的是:给出递归解法的图示、简化高位零的删除过程,以便桂桂卷和大家都能更好地理解大数打印的递归解法。

桂桂卷给出n=2的情况,其他情况类似。

递归图示

(1)num[0]=0,num[1]=0,1,…,9 image (2)num[0]=1,num[1]=0,1,…,9 image (3)依此类推,当num[0]从0至9循环结束时,res数组生成完毕,此时res=[00, …, 09, 10,…19, …, 90, …, 99],算法结束。 image

桂桂卷进击之路—简化高位零的删除过程

大神题解的高位删除算法使用了两个变量:nine、start。琢磨了一天,本桂酱还是没有理解透( ‘-ωก̀ )

于是就按着自己的想法,给出只使用start变量的解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
    def printNumbers(self, n: int) -> List[int]:
        def dfs(x):
            if x == n:
                s = ''.join(num[self.start:])
                if s != '0': res.append(int(s))
                return
            for i in range(10):
                num[x] = str(i)
                dfs(x+1)
            if self.start>0: self.start -= 1
        num, self.start, res = ['0']*n, n-1, []
        dfs(0)
        return res

解题思路:直观来看,几次for循环就意味着几次进位, 所以在每次for循环之后start变量减1就可以控制删除几个高位零了。但有一点值得注意的是,高位遍历的时候,个位会遍历多次,也就是说个位的一次完整for循环,有时候并不真正代表一次进位。这种时候只需要给start变量加一层判断:当start为零时便不再往下减就行了。(ฅ´ω`ฅ)

好啦,大数打印的递归图示以及高位删除过程的简化到这里就分析完毕咯。

桂桂卷祝大家吃到好吃的晚餐,明天依旧生活愉快嗷ψ(`∇´)ψ

image