2021.05.13字典序第k小数字

本文介绍了一种高效算法,用于寻找1到n范围内字典序第k小的数字。通过构建十叉搜索前缀树并采用递归策略,解决了如何计算特定前缀下的子节点数量问题,进而迭代确定目标数字。

2021.05.13字典序第k小数字

(题目来源:https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/)

题目描述

给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。

数据规模和约定

1 ≤ k ≤ n ≤ 10^9。

思路

搜索第k小数字时可以构造一个“十叉搜索前缀树”,如下图:

在这里插入图片描述

我们可以发现 ①这个十叉搜索树是一个完全十叉树,但不是一个满十叉树,其最后一个节点即为n。②前序遍历1,10,101,102…即为其按照字典序升序排列的顺序。
为求解该问题,我们需要解决三个子问题:

子问题1:如何找到一个前缀下所有子节点的个数?
可以发现,如果是满二叉树,那么同一层前缀下的子节点个数是相等的:

在这里插入图片描述

所以可以采取如下策略,即cur从10开始遍历,next从11开始遍历,如果没有到达底部(即cur < n),那么往下一层遍历,即cur*=10, next *= 10,10前缀下的子节点个数为110-100 = 10; //cur为遍历过程中指定prefix下的cur根节点。

子问题2和3:如果第k个数在当前前缀下,那么我们该如何遍历到它?如果第k个数不在当前前缀下,我们又该如何继续遍历?

如果第k个数在当前前缀的子树中,那么往下一层进行遍历,否则进入当前层的下一前缀树进行搜索。依次迭代。

代码

	public int findKthNumber(int n, int k) {
		int cur = 1;
		int prefix = 1;
		while(cur < k) {
			int tmp = count(n,prefix);
			if(tmp + cur > k) { //res在此节点下
				prefix *= 10;
				cur++;
			} else { //res不在此节点下
				cur += tmp;
				prefix++;
			}
		}
		
		return prefix;
    }
	
	//返回当前前缀为根的子节点个数
	int count(int n, int prefix) {
		long cur = prefix;
		long next = cur+1;
		int cnt = 0;
		while(cur <= n) {
			cnt += Math.min(n+1, next)-cur;
			next *= 10;
			cur *= 10;
		}
		return cnt;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值