问题描述
给定一个整数 nn ,请你在 1 到 n中找出字典序排序后第 k 个数字。例如,当 n 为 11 , k 为 3 时,字典序如下:
1,10,11,2,3,4,5,6,7,8,9
因此,第 3个数字是 11 。
输入格式
输入两个整数 n和 k,(1≤n,k≤10的9次方)(1≤n,k≤10的9次方)。
输出格式
输出一个整数,表示字典序排列后第 k个数字。
样例:
输入:13 2 输出:10
题目解读:
①字典序排序的本质是将输入的int看成字符串,依次进行排序 如n=11,从1到11排序,开头为1的数有1,10,11,依次比较这三个,1>10>11,所以字典序为1,10,11 ,再看1-11的数里2开头的只有一个,所以1>10>11>2如此排序.....
②从题目给的数据大小来看,不能用暴力解法(但下文给出了暴力解法,官网通过率20% T = T),因此我们想到决策树来模拟字典序排序。
暴力代码如下:
n,k = map(int,input().split())
def zidianxu(n, k):
sort_num = sorted(str(i)for i in range(1,n+1))
return sort_num[k-1]
ans = zidianxu(n,k)
print(ans)
模拟字典序排列的思路:
核心思想:逐位确定数字;从最高位到最低位逐位确认
计算子树的大小:对于当前的前缀,计算以该前缀开头的数字的数量
根据k和子树的大小 共同决定下一步:如果k<=当前前缀的字数大小,则进入该子树,否则跳过并继续处理下一个前缀。
重复操作以上步骤到确定所有位。时间复杂度为 O(1).
def find_kth_number(n, k):
def count_prefix(prefix, n):
"""计算以 prefix 为前缀的数字的数量"""
count = 0
current = prefix
next_prefix = prefix + 1
while current <= n:
count += min(n + 1, next_prefix) - current
current *= 10
"""方便快速运算"""
next_prefix *= 10
return count
result = 1
k -= 1 # 将 k 转换为 0 索引
while k > 0:
# 计算以 result 为前缀的数字的数量
cnt = count_prefix(result, n)
if k >= cnt:
# 如果 k 大于 cnt,则跳过该子树
result += 1
k -= cnt
else:
# 否则,进入该子树
result *= 10
k -= 1
return result
n,k = list(map(int,input().split()))
ans = find_kth_number(n,k)
print(ans)