Leetcode0386. 字典序排数(medium,字典树)

这篇博客探讨了如何使用O(n)时间和O(1)空间复杂度解决字典序排列问题。通过构建一个隐式的10叉树并进行深度优先搜索,博主给出了Python代码实现,并对比了两种不同的解决方案。文章还提到了先前遇到的类似问题,以及对解题思路的深入理解。
摘要由CSDN通过智能技术生成

目录

1. 问题描述

2. 解题分析

3. 代码实现


1. 问题描述

给你一个整数 n ,按字典序返回范围 [1, n] 内所有整数。

你必须设计一个时间复杂度为 O(n) 且使用 O(1) 额外空间的算法。

示例 1:

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

示例 2:

输入:n = 2
输出:[1,2]

提示:

  • 1 <= n <= 5 * 10^4

2. 解题分析

         将所有小于等于 n 的数字按照字典序的方式,可以构建字典树如下(以1为根节点,然后每个节点i的子节点为 (10*i, 10*i + 1, ..., 10 *i + 9)),这个可以看作是一个10叉树:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56yo54mb5oWi6ICV,size_20,color_FFFFFF,t_70,g_se,x_16

        构建完这个树后,按照前序遍历即可以得到字典序排序结果。而前序遍历是可以用深度优先搜索的方式得到的。

        当然,这个字典树不必显式地构建出来,我们可以直接基于深度优先搜索给出字典序排序结果。基本流程如下:

  1.         初始化:将0入栈
  2.         从栈中取出一个数x,加入结果列表
  3.         将x在字典树上的子节点(10x+9,10x+8,...,10x)中大于等于0小于等于n的数入栈
  4.         重复以上步骤2,3直到栈变为空

        以上有两点细节要注意:

        (1)虽然0并不需要,但是从0入栈开始,可以让程序变得简洁一些。最后从结果中要去掉0,而且在取邻节点入栈时,要排除0

        (2)邻接点入栈时,是按倒序入栈。比如说1的子节点是按照19,18,...的顺序入栈,这样它们被取出时是按照所希望的顺序出栈    

3. 代码实现

import time
from typing import List
from collections import deque

class Solution:
    def lexicalOrder(self, n: int) -> List[int]:
        
        q = deque([0])
        ans = []
        while len(q)>0:
            x = q.pop()
            ans.append(x)
            # for k in range(10):
            for k in range(9,-1,-1):
                y = 10*x+k
                if 0 < y <= n:
                    q.append(y)
        return ans[1:]

if __name__ == "__main__":
    
    sln = Solution()
    n   = 5*10**4
    tstart = time.time()
    ans = sln.lexicalOrder(n)
    tstop = time.time()
    print('n={0}, ans={1}, tcost={2:4.2f}'.format(n,ans,tstop-tstart))

        执行用时:140 ms, 在所有 Python3 提交中击败了37.39%的用户

        内存消耗:18.6 MB, 在所有 Python3 提交中击败了86.94%的用户

        好像这是碰到的第2道字典序的题目,上一次是difficult级别的leetcode440(Leetcode0440. 字典序的第K小数字(difficult,三种算法)),当时没有字典序的概念,死磕了很久最后只好求助于官解。有了上次的铺垫,这次就轻松多了,几分钟搞定。

        不过,官解的解法更加高效(运行时间只有上面我的解法的五分之一):

class Solution:
    def lexicalOrder(self, n: int) -> List[int]:
        ans = [0] * n
        num = 1
        for i in range(n):
            ans[i] = num
            if num * 10 <= n:
                num *= 10
            else:
                while num % 10 == 9 or num + 1 > n:
                    num //= 10
                num += 1
        return ans

        回到主目录:笨牛慢耕的Leetcode每日一解题解笔记(动态更新。。。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨牛慢耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值