题目链接:zyb的面试
参考博客:[LeetCode] K-th Smallest in Lexicographical Order 字典顺序的第K小数字
【题目】:
今天zyb参加一场面试,面试官听说zyb是ACMer之后立马抛出了一道算法题给zyb:
有一个序列,是1到n的一种排列,排列的顺序是字典序小的在前,那么第k个数字是什么?
例如n=15,k=7, 排列顺序为1, 10, 11, 12, 13, 14, 15, 2, 3, 4, 5, 6, 7, 8, 9;那么第7个数字就是15.
那么,如果你处在zyb的场景下,你能解决这个问题吗?
【题解】:
题目:就是n个数按照字典序的,找第K小的数。
想法:画个图,看出来这个题目和之前Sequence subset (杭电新生100题)很类似,但是注意,这个题目不是满10叉树,因为题目给定的是N,这明显不是一颗整齐的树。
做法:
参考博客后发现一个特别的方法:如果我想 求一个节点子树的节点数只要求两个差值即可。
就是当前节点和下一个节点的两个的差值。
然后知道子树的个数后,如果还够不着K,那么就右移,如果在期间,就往下探索。
具体看代码:
#include<bits/stdc++.h>
using namespace std;
void Find_Kth_Number(int n,int k){
int cur = 1 ;
k-- ;
while ( k > 0 ){
int S = cur , E = cur + 1 , Size = 0 ;
// S 是当前节点,E是下一个节点,Size是两个节点之间的个数
while ( S <= n ){
//如:20-10=10,说明10~19该层有10个数,
//又如:200 - 100, 说明100~199有100个数
//通过两个节点之间的差值可以求出 节点统治的子树大小
Size += min ( E-S , n-S+1);
S *=10;
E *=10;
}
if ( Size > k ){
//如果 Size>k,说明在这个节点下面
cur *=10;
k--;
}else {
//否则,说明不在这个节点
cur++;
k-=Size;
}
}
printf("%d\n",cur);
}
int main()
{
int T,n,k;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
Find_Kth_Number(n,k);
}
return 0;
}