import java.util.*;
/**
* NC334 字典序第K小
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 类似 -> NC362 字典序排列 [nowcoder]
*
* @param n int整型
* @param k int整型
* @return int整型
*/
public int findKth(int n, int k){
// return solution1(n, k);
return solution2(n, k);
}
private int seq = 0;
private int ans = 0;
/**
* Trie(字典树/前缀树) - 超时!
* @param n
* @param k
* @return
*/
private int solution1(int n, int k){
Trie trie = new Trie();
for(int num=1; num<=n; num++){
trie.insert(String.valueOf(num));
}
preorder(trie, "", k);
return ans;
}
/**
* 树的前序遍历
* @param trie
* @param num
* @param k
*/
private void preorder(Trie trie, String num, int k){
if(seq >= k){
return;
}
if(trie == null){
return;
}
if(trie.isEnd){
if(++seq == k){
ans = Integer.parseInt(num);
return;
}
}
for(int i=0; i<=9; i++){
preorder(trie.children[i], num+i, k);
}
}
/**
* Trie类
*/
private class Trie {
Trie[] children;
boolean isEnd;
public Trie(){
children = new Trie[10];
isEnd = false;
}
public void insert(String num){
Trie cur = this;
int idx;
for(char digit: num.toCharArray()){
idx = digit-'0';
if(cur.children[idx] == null){
cur.children[idx] = new Trie();
}
cur = cur.children[idx];
}
cur.isEnd = true;
}
}
/**
* 模拟Trie(无需实际构造)
* @param n
* @param k
* @return
*/
private int solution2(int n, int k){
// 当前数指针
int cur = 1;
k--;
int cnt;
while(k > 0){
// 获取以当前数cur为根的树的所有节点数(包括当前数)
cnt = cntNodes(cur, n);
// 不在tree(cur)[以cur为根的树]中
if(cnt <= k){
// 当前数指针 右移
cur++;
k -= cnt;
}
// 必在tree(cur)[以cur为根的树]中
else{
// 当前数指针 下移
cur *= 10;
k--;
}
}
return cur;
}
/**
* 获取以当前数cur为根的树的所有节点数(包括当前数)
* @param root
* @param n
* @return
*/
private int cntNodes(int root, int n){
int cnt = 0;
long left = root;
long right = root;
while(left <= n){
// 当前层的数目
cnt += Math.min(right,n)-left+1;
left = left*10;
right = right*10+9;
}
return cnt;
}
}