面試題44:數字序列中某一位的數字
一、題目描述
數字以0123456789101112131415…的格式序列化到一個字符序列中。在這個序列中,第5位(從0開始計數)是5,第13位是1,第19位是4,等等。請寫一個函數求任意位對應的數字。
二、問題分析
這個尋求高效的解決方法,也是尋找規律:
- 個位數的個數一共有10個,即0~9,共佔了10*1位數字;(特殊)
- 兩位數的個數一共有90個,即10~99,每個數字佔兩位,共佔了90*2位數字;
- ……
- m位數的個數一共有9*10^(m-1)個,每個數字佔m位,佔了9*10^(m-1)*m位數字。
判斷第n個對的數字是屬於幾位數,再從幾位數中進行尋找。
舉個例子:
0123456789101112131415161718192021…
我們要取第33位。
爲了更形象,我們把上面的規律抽象成比較直觀的場景:我們把實際的數字想成它們在一個個方格里面存儲。一個方格可能儲存多個數字。
首先我們要找出第33位的字符對應的數字的位數。因爲個位數的個數有10個,兩位數的個數有90個,33介於10-100之間,可以確定是兩位。
利用一個方格存儲兩位的特點:
(33-10 )/2 得出11,這個數字加上10 就得出了第33位字符對應的數字是 21
(33-10)%2 得出 我們要的字符是 對應數字的第1位 即1
三、問題解答
public int digitAtIndex(int index) {
if(index<0){
return -1;
}
// m位數
int m=1;
while(true) {
// m位數的個數
int numbers=numbersOfIntegers(m);
if(index<numbers*m) {
return getDigit(index,m);
}
index-=numbers*m;
m++;
}
}
// 返回m位數的總個數
private int numbersOfIntegers(int m) {
if(m == 1) {
return 10;
}
return (int) (9*Math.pow(10, m-1));
}
// 獲取數字
private int getDigit(int index, int m) {
// 對應的m位數
int number = getFirstNumber(m)+index/m;
// 在數字中的位置
int indexFromRight = m - index%m;
for(int i=1; i < indexFromRight; i++) {
number/=10;
}
return number%10;
}
// 第一個m位數 例如第一個兩位數是10,第一個三位數是100
private int getFirstNumber(int m) {
if(m==1) {
return 0;
}
return (int) Math.pow(10, m-1);
}