蓝桥杯每日一题----第k个数

题目:第k个数

主要为了学习数字的构造方法,如何快速求1~n中前缀为pre的数字的个数。

题目分析

一开始想的是把数字转化为字符串,然后丢给sort排序就行了,但是n太大了,会出现溢出问题。走到这里也从侧面反映了对所有的数字排序然后输出第k个数字的方法是不可取的,那么可不可以直接构造出第k个数字呢?

首先查找一下以1开头的数字个数,假设是在1~321里面寻找,那么以1开头的数字有1+10+100=111个,如果k=13<111,说明可以确定排序为k的数字的第一位就是1,那么再枚举下一位,下一位枚举以10开头的数字个数(这里1是已经确定的,但是呢1也是以1开头的,在枚举10的时候相当于舍弃了数字1,所以这里要k--,减掉数字1)有1+10=11个,假设k=12>11,那么说明排序为k的数字的第二位不是0,那么按照字典序枚举下一个数字,但是此时,我们可以把以10开头的数字舍弃掉了,所以k-=11,k=1。即查找以11开头的数字的个数有1+10=11个,假设k<11,说明排名为k的数字是以11开头的,然后再找110开头的数字的个数是1个,刚好和k相等,说明我已经找到那个数字了,就是110。

我们自己按照字典序排一下,看一看是不是,

1,10,101,102,103,104,105,106,107,108,109,11,110

可以看到110刚好排在第13的位置,说明我们上面分析的过程是对的。接下来看一下刚刚那个代码应该怎么写。

java 复制代码
 Scanner scanner = new Scanner(System.in);
 int n = scanner.nextInt();//数据范围为1~n
 int k = scanner.nextInt();//找字典序排名为第k的数字
  int cur = 1;//从以数字1开头的数字开始尝试
  while(k > 0) {
        long nums = get(n,cur,cur+1);//找以cur开头的数字的个数,具体怎么找后续讨论
        if(k==nums&&k==1) {//如果k和nums相等或者不相等,但是k=1了,都说明当前的数字cur就是我们要找的数字,
            System.out.println(cur);
            return;
        }
        if(nums < k) {//当前数字个数小于k,说明不是以cur开头的,就找下一个,即cur+1,同时排除掉以cur开头的数字,所以k-=num
            cur += 1;
            k -= nums;
        }else {//当前数字个数大于k,说明是以cur开头的,那么就令cur*=10,然后再接着找下一位应该是以啥开头,cur*=10说明我们舍弃了cur本身,所以这里k要减1
            cur *= 10;
            k -= 1;
        }
    }

接下来就是如何求以cur开头的数字个数了

方法一

假设求1~123中以cur=1开头的数字个数,这里再加一个辅助的cur1,cur1=cur+1=2,

数字位数为1位时:cur1-cur=2-1=1;

cur1*=10;cur*=10;

数字位数为2位时:cur1-cur=20-10=10;

cur1*=10;cur*=10;

数字位数为3位时:cur1-cur=200-100=100;(×)

我们达不到200,只能达到123,所以应该是

数字位数为3位时:min(cur1,n+1)-cur=123+1-100=24;

总结:

数字位数为p位时:num+=min(cur1,n+1)-cur;

所以这里的代码为,

java 复制代码
private static long get(int n, long cur, long cur1) {
    // TODO Auto-generated method stub
    long nums = 0;//统计以cur开头的数字的个数
    while(cur <= n) {
        nums += Math.min(n+1, cur1)-cur;
        cur *= 10;
        cur1 *= 10;
    }
    return nums;
}

方法二

假设求1~123中以cur=1开头的数字个数,

base=cur=1;max=cur=1;

数字位数为1位时:max-base+1=1-1+1=1;

base*=10=10;max=max10+9=19;
数字位数为2位时:max-base+1=19-10+1=10;
base
=10=100;max=max*10+9=199;

数字位数为3位时:max-base=199-100+1=100;(×)

我们达不到200,只能达到123,所以应该是

数字位数为3位时:min(max,n)-base+1=123-100+1=24;

总结:

数字位数为p位时:num+=min(max,n)-base+1;

所以这里的代码为,

java 复制代码
private static long get2(int n, long cur) {//13 1
    // TODO Auto-generated method stub
    long nums = 0;//统计以cur开头的数字的个数
    long base = cur;//19 13-10+1
    long max = cur;//10
    while(base <= n) {
        nums += Math.min(n, max)-base+1;
        max =max * 10+9;//和base位数相同但是是该位数下以cur开头的最大的数字
        base *= 10;
    }
    return nums;
}

全部代码

java 复制代码
import java.util.Scanner;

public class Main{
public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int n = scanner.nextInt();
    int k = scanner.nextInt();
    int cur = 1;
//    k--;
    while(k > 0) {
//        long nums = get(n,cur,cur+1);
        long nums = get2(n,cur);
        if(k==nums&&k==1) {
            System.out.println(cur);
            return;
        }
//        System.out.println(cur + " " + nums);
        if(nums < k) {//当前字符个数小于k
            cur += 1;
            k -= nums;
        }else {
            cur *= 10;
            k -= 1;
        }
    }
    System.out.println(cur);
}

private static long get(int n, long cur, long cur1) {
    // TODO Auto-generated method stub
    long nums = 0;//统计以cur开头的数字的个数
    while(cur <= n) {
        nums += Math.min(n+1, cur1)-cur;
        cur *= 10;
        cur1 *= 10;
    }
    return nums;
}

private static long get2(int n, long cur) {//13 1
    // TODO Auto-generated method stub
    long nums = 0;//统计以cur开头的数字的个数
    long base = cur;//19 13-10+1
    long max = cur;//10
    while(base <= n) {
        nums += Math.min(n, max)-base+1;
        max =max * 10+9;//和base位数相同但是是该位数下以cur开头的最大的数字
        base *= 10;
    }
    return nums;
}
}

测试结果

相关推荐
Kenneth風车16 分钟前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)11
算法·机器学习·分类
最后一个bug21 分钟前
rt-linux中使用mlockall与free的差异
linux·c语言·arm开发·单片机·嵌入式硬件·算法
蹉跎x1 小时前
力扣1358. 包含所有三种字符的子字符串数目
数据结构·算法·leetcode·职场和发展
rainoway2 小时前
CRDT宝典 - yata算法
前端·分布式·算法
坊钰2 小时前
【Java 数据结构】移除链表元素
java·开发语言·数据结构·学习·链表
巫师不要去魔法部乱说2 小时前
PyCharm专项训练4 最小生成树算法
算法·pycharm
IT猿手3 小时前
最新高性能多目标优化算法:多目标麋鹿优化算法(MOEHO)求解GLSMOP1-GLSMOP9及工程应用---盘式制动器设计,提供完整MATLAB代码
开发语言·算法·机器学习·matlab·强化学习
阿七想学习3 小时前
数据结构《排序》
java·数据结构·学习·算法·排序算法
王老师青少年编程3 小时前
gesp(二级)(12)洛谷:B3955:[GESP202403 二级] 小杨的日字矩阵
c++·算法·矩阵·gesp·csp·信奥赛
Kenneth風车3 小时前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
算法·机器学习·分类