由於這道題目在牛客上沒有,所以在此記錄一下。
一.題目大意:
數字以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型的,否則當數據比較大的時候,就不支持了。