题目描述
数字以01234567891011121314…的格式序列化到一个字符序列中。在这个序列中,第5位是5(从0开始),第13位是1,第19位是4,等等。请写一个函数,求任意第n位对应的数字。
最直观的方法就是从0开始逐一枚举每个数字。每枚举一个数字,就求出该数字是几位数,并把该数字的位数和前面所有数字的位数累加。如果位数之和仍然小于或者等于输入n,则继续枚举下一个数字。当累加的数位大于n时,那么第n位数字一定在这个数字里,再找出对应的那一位。
换种思路,我们可以跳过若干个数字,找数字见的规律来求对应的数字。以求序列中1001位为例:
序列的前10位是0~9,所以第1001位一定在10之后,因此这10个数可以直接跳过。我们再从后面紧跟的序列中找到第991(991=1001-10)位的数字。
接下来180位数字是10~99的两位数。由于991>180,所以第991位所有的两位数之后。我们再跳过90个两位数,继续从后面找881(881=991-180)位。
接下来的2700位是900个100~999的三位数中的一位。由于881<2700,所以第881位是某个三位数中的一位。由于881=270+1,这意味着第881位是从100开始的第270个数字370的中间位,也就是7 。
于是可有以下代码:
package sword_offer;
// page 225 数组序列中的某一位数字
import java.lang.Math;
public class Solution44 {
// 这里没采用原文中将程序拆分为几个小程序的形式,考虑到个位数的特殊性,直接在前面处理
public static int digitAtIndex(int index) {
if (index < 10) return index;
int n = 2; //位数
index = index - 10;//初始化位位数为1的个数
while(true) {
int numsOfN = 9 * (int) Math.pow(10, n - 1); //n位的个数
if (index < numsOfN * n) { //是否在这个区间
int number = (int) Math.pow(10, n - 1) + index / n; //对应的整数
int indexFromRight = n - index % n; //从右边数第几位
for (int i = 1; i < indexFromRight; i++) { //找到那一位
number /= 10;
}
return number % 10;
}
index -= numsOfN * n;
n++;
}
}
// 测试
public static void main(String[] args) {
System.out.println(digitAtIndex(1001));
}
}