1. 程式人生 > >08頭條實習生面試_字典序的第K小數字

08頭條實習生面試_字典序的第K小數字

LeetCode(440)

字典序的第K小數字

思路:

其實這是一個"十叉樹",如下圖:

1)每個節點的子節點可以有十個,比如節點1的子節點可以是10~19、節點2的位元組的可以是20~29、。。。

但是由於n大小的限制,構成的並不是一個"滿十叉樹"。

2)分析題目中給的例子可以知道,數字1的子節點有4個(10,11,12,13),而後面的數字2到9都沒有子節點,

那麼這道題實際上就變成了一個先序遍歷十叉樹的問題。

3)那麼,難點就變成了 計算出同一層兩個相鄰的節點的子節點的個數,也就是程式碼中的steps

  3.1)當前節點為 curr  (從curr = 1 開始),則同一層的下一個節點為 curr+1;

  3.2)計算節點 curr到節點curr+1之間的子節點個數steps

     3.2.1)如果子節點個數 大於 k,說明第k小的樹一定在子節點中,

              繼續向下一層尋找:curr *=10;

              k -= 1;(原因:向下一層尋找,肯定要減少前面的父節點,即 在上一層中的第k個數,在下一層中是第k-1個數)

     3.2.2)如果子節點個數 小於或者等於 k,說明第k小的樹不在子節點中,

              繼續向同一層下一個節點尋找:curr +=1;

              k -= steps;(原因:向下一層尋找,肯定要減少前面的所有的位元組點)

   以此類推,直到k為0推出迴圈,此時cur即為所求。

原始碼如下:

package Practise;

import java.util.Scanner;

public class Main8 {
    public static int findKthNumber(int n, int k) {
        int curr = 1;
        k = k - 1;
        while (k > 0) {
            long steps = 0, first = curr, last = curr + 1;
            while (first <= n) {
                steps += Math.min((long)n + 1, last) - first;
                first *= 10;
                last *= 10;
            }
            if (steps <= k) {
                curr += 1;
                k -= steps;
            } else {
                curr *= 10;
                k -= 1;
            }
        }
        return curr;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int k = sc.nextInt();
        System.out.println(findKthNumber(n,k));
    }
}