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

来源:互联网 发布:vb 数组长度 编辑:程序博客网 时间:2024/06/16 11:34

题目描述

给定整数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

数据范围

  • 对于20%的数据, 1 <= m <= n <= 5 ;
  • 对于80%的数据, 1 <= m <= n <= 10^7 ;
  • 对于100%的数据, 1 <= m <= n <= 10^18.

思路一

n个int数据转为string类型,然后sort排序,得到m位置的string,再转为int型。
缺点:只通过了部分用例,数据量大时,会timeout。其二,数据会超过数组最大长度。

思路二

字典树的方法。十叉树,n+1个节点,根节点为0,不纳入计算,求深度遍历,第m个节点。
树的排列如下:
- 第一层是root 0;
- 第二层依次是:1,2,3,4,5,6,7,8,9;
- 第三层依次是:10,11,12,13,14,15,16,17,18,19,20,21……;
步骤:
1. 计算节点1分支中,小于n的节点个数p,得到p个节点。
2. 如果p>=m,说明第m个节点在1分支上,去掉1节点,则从第二层开始,重复操作,m=m-1。相当于重新回到最初,从10开始的第m个数,当前节点值为1。
3. 如果p< m,说明第m个节点在其他分支上,则从值为2的节点开始,重复操作,m=m-p。相当于回到最初,从2开始的第m个数。
4. 何时停止?m=0时,当前节点即为所求值。
代码:

import java.util.Scanner;public class Main {    public static void main(String[] args) {          Scanner scan = new Scanner(System.in);          long n = scan.nextLong(), m = scan.nextLong();          long result = 1;          while(m!=0)        {            //当前节点为result,result分支上得到小于n的节点个数            long p=getCntOfChild(result,n);            if(m>p)            {                //第m个数不在result节点的分支上                m-=p; // 去掉result分支上小于n的节点                result++;// 当前节点设置为result右边第一个节点            }else {                m--;// 去掉result节点                if(m==0) //第m个数是result节点                    break;                result*=10; //第m个数在result节点的分支上,当前节点设置为result节点分支最左节点            }        }        System.out.println(result);      }      // 找到小于n的,以p开头的树的个数       //例如:result=1,n=20,则 p=11,节点依次为:1,10,11,12,13,14,15,16,17,18,19    private static long getCntOfChild(long p,long n) {          long sum=1; //p节点        // p的下层有10个数        // n 需要小于当前 节点子节点最大值,也就是最右边节点         for(long level=10; n>=level*p;level*=10)        {            //n 大于最右节点            if(n>=level*p+level-1)            {                sum+=level;  //当前 节点子节点个数为level            }else            {                // n 大于最左节点,n小于最右节点                sum+=(n-level*p+1);            }        }        return sum;      }  }

刷题感受

  1. 测试用例数据量大,考虑long数据类型,一般的sort等方法避免采用;
  2. 算法题,基本与数据结构相关,考虑数据特性,比如这里的树结构;
  3. 学会抽象,讲当前题目进行抽象成一般问题,极好解决,比如上述题目就是树节点遍历的问题。
  4. 祝好,以上,刷题不易,AC不易。
原创粉丝点击