數字序列中某一位數字(《劍指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型的,否則當數據比較大的時候,就不支持了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM