zoukankan      html  css  js  c++  java
  • 数字序列中某一位数字(《剑指offer》面试题44)

    由于这道题目在牛客上没有,所以在此记录一下。

    一.题目大意:

    数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从0开始计数,即从第0位开始)是5,第13位是1,第19位是4,等等。请写一个函数,求任意第n位对应的数字。

    二.题解
    《剑指offer》上提供了两种思路。

    方法1:

    第一种思路是:从0开始枚举每个数字。每枚举一个数字的时候,求出该数字是几位(如15是2位数、9323是4位数),并把该数字的位数和前面所有数字的位数累加。如果位数之和仍然小于等于n,则继续枚举下一个数字。当累加的数位大于n时,那么第n位数字一定在这个数字里。(此处为什么是大于而不是大于等于?因为是从0开始计数的,实质应为第n+1位)该算法的时间复杂度为O(N),当N很大时(如N = 10 ^ 11)往往会超时。

    方法2;

    这种方法是本文论述的重点,其实本提可以采用和文章http://www.cnblogs.com/wangkundentisy/p/8920147.html中的第二题的方法4类似。我们令f(m)表示"从0~长度为m的最大的数字"的数字个数之和,由此我们可以继续分析:

    f(0) = 0

    f(1) =10 + 0 = 10 (对应0 ~ 9)

    f(2) =90 * 2 + f(1) = 190 (对应10 ~99, 0 ~ 9)

    f(3) =900 * 3 + f(2) = 2890 (对应100 - 999,0 ~ 99)

    f(4) = 9000 * 4 + f(3) =38890 (对应1000 ~ 9999,0 ~ 999)

    ....

    f(m) = 9 * 10^(i - 1) * m + f(m-1)

    其中m表示数字的长度。求出f(m)之后,剩下的就比较好解了。

    对于数字n,我们只需要比较n与数组f中每个元素,如果f(k) >= n,其中k是满足前面条件的最小值,那么我们就可以确定最终的数字长度一定是k了。所以令n = n - f(k - 1),然后根据n / k和n % k的结果,就能知道最终的数字R和R中的哪个位置。

    举个例子:

    假设 n = 1001,由于f(2) < 1001且f(3) > 1001,所以最终的数字一定是3位数的数字。令n = n - f(2) = 811。有811 / 3 =270  ,811 % 3 = 1。所以最终的数字为100 + 270 = 370,且是370中的第1位数(从0开始计数),所以最终的结果是7。

    具体代码如下:

    #include<iostream>
    #include<unordered_map>
    #include<queue>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<sstream>
    using namespace std;
    #define max_len 9
    int TheNthDigit(long long f[],int n)
    {
        if(n < 0)
            return -1;
        if(n <= 9)
            return n;
        int pos = 0;
        for(int i = 1; i <= max_len ;i++)
            if(f[i] >= n)
             {
                 pos = i;
                 break;
             }
        n = n - f[pos - 1];
        int temp1 = n / pos;
        int temp2 = n % pos;
        int temp3 = temp1 + pow(10, pos - 1);
        return (int)(temp3 / pow(10,pos - temp2 -1)) % 10;
    
    }
    int main()
    {
        long long f[] = {0,10,190,2890,38890,488890,5888890,68888890,788888890,8888888890};//初始化长度数组
        int n;
        cin >> n;
        cout<<TheNthDigit(f,n)<<endl;
    }
    

    该算法的时间复杂度为常数级,并且此处的代码支持的数字最大长度为9,即 N = 999999999。当然你可以任意调整,但数组f也需要相应的调整。

    有几点需要注意:

    1.当n <= 9时,这个通用的公式就不支持了,需要单独处理。

    2.此处同http://www.cnblogs.com/wangkundentisy/p/8920147.html一样,我是事先算出的数组f的各个值。当然也可以在代码中迭代计算,但是我不建议这么做。因为要利用的pow函数,而pow函数的返回值是double类型,它在其强制转换成整型或长整型的过程中,有可能会有误差,最终导致计算结果不准确。所以我建议最好是事先算出来数组f的各个元素,况且f中的元素并不难计算,都是有规律的。

    3.还有需要注意的一点是数组f一定是long long型的,否则当数据比较大的时候,就不支持了。

  • 相关阅读:
    QT添加托盘代码
    2010年左右我说要做一个操作系统的时候,绝大多数人以为那是天方夜谭,是堂吉诃德式的行为。今天,我们讨论YunOS会成为一个新的生态和创新平台,更多人相信这件事是可能的。
    台哥算法练习:八皇后问题
    台哥算法练习 汉诺塔问题
    台哥算法练习:数组排序的几种算法
    面试遇到的两道算法题
    台哥算法练习 50人围圈报数
    台哥算法练习 自己写的一个LinkedList
    台哥算法练习 自己写的一个ArrayList
    台哥算法练习 寻找和为某值的子集
  • 原文地址:https://www.cnblogs.com/wangkundentisy/p/8963605.html
Copyright © 2011-2022 走看看