字典序(今日头条2017秋招真题)

字典序(今日头条2017秋招真题)

给定整数n和m,将1到n的这n个整数按字典序排列之后,求其中的第m个数字。

对于n = 11,m = 4,按字典序排列依次为1, 10, 11, 2, 3, 4, 5, 6, 7, 8, 9,因此第4个数字为2。


输入
输入仅包含两个整数n和m。

样例输入
11 4

输出
输出仅包括一行,即所求排列中的第m个数字。

样例输出
2

时间限制
C/C++语言:1000MS其它语言:3000MS
内存限制
C/C++语言:65536KB其它语言:589824KB


package Test;

import java.util.Scanner;

public class Test5 {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        long n = scan.nextLong(); //12248924213738476l;
        long m = scan.nextLong(); //223284412422892l;
        scan.close(); //10200955971180594

        long k = 1; //answer,从1开始找
        //十叉树
        while (m > 0) {
            long count = getCount(k, n); //以k开头且小于等于n的节点个数
            if (count < m) { //第m个数不在k节点的分支上
                m -= count; // 去掉k分支上小于n的节点
                k++;// 当前节点设置为k右边第一个节点
            } else {
                m--; // 去掉k节点
                if (m == 0) //第m个数是k节点
                    break;
                k *= 10; //第m个数在k节点的分支上,当前节点设置为k节点分支最左节点,如1的下一层开始时10
                //也就是进入更深一层的分支,比如我们已经知道它在1的分支上了,下一次就判断在不在10的分支上,再判断在不在100的分支上
            }
        }

        System.out.println(k);
    }

    //返回此子树中以start开头且小于等于n的节点个数
    //例如:start=1,n=20,则 cnt=11,节点依次为:1,10,11,12,13,14,15,16,17,18,19
    private static long getCount(long start, long n) {
        long base = 10, cnt = 1; //cnt个节点,1表示它本身
        while (start * base <= n) { //下一层,10个数,再下,100...。这一步就是尝试着加0
            if (start * base + (base - 1) <= n) { //最右节点小于n
                cnt += base; //这一层全加
            } else { //最左节点小于n或最右节点大于n,则只能加左边一部分
                cnt += (n - base * start + 1);
            }
            base *= 10;
        }
        return cnt;
    }


}
posted @ 2020-04-06 11:14  别再闹了  阅读(150)  评论(0)    收藏  举报