题目描述
数字以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 。
于是可有以下代码:
using System;
namespace 数字序列中某一位的数字
{
class Program
{
static void Main(string[] args)
{
int num1 = 5, num2 = 158, num3 = 1001, num4 = 0, num5 = -100;
Solution s = new Solution();
Console.WriteLine("Test1\nPosition:{0}\t\t\t" + s.DigitAtIndex(num1),num1);
Console.WriteLine("Test2\nPosition:{0}\t\t\t" + s.DigitAtIndex(num2),num2);
Console.WriteLine("Test3\nPosition:{0}\t\t\t" + s.DigitAtIndex(num3),num3);
Console.WriteLine("Test4\nPosition:{0}\t\t\t" + s.DigitAtIndex(num4),num4);
Console.WriteLine("Test5\nPosition:{0}\t\t\t" + s.DigitAtIndex(num5),num5);
}
}
class Solution
{
/// <summary>
/// 查找格式化序列中第index位的数字
/// </summary>
/// <param name="index">查找的数字的位置</param>
/// <returns>查找到的数字</returns>
public int DigitAtIndex(int index)
{
if (index < 0)
return -1;
int digit = 1; //位数,从1开始
while (true)
{
int numbers = CountOfDigit(digit); //计算有多少个当前位的数字,如digit为2,那么计算的就是有多少个二位数(10~99)
//如果数字在当前位,则计算出在当前位的哪个数字的哪个位置上,返回他
if (index < digit * numbers)
return DigitAtIndex(index, digit);
index -= digit * numbers; //如果第n位不在当前位的数字中,那么就减去当前位所有数字在序列中占得数量
digit++; //位数+1
}
}
/// <summary>
/// 找到序列中第index位的位置
/// </summary>
/// <param name="index">格式化序列中所在的位置</param>
/// <param name="digit">所在的位数</param>
/// <returns>对应的数字</returns>
private int DigitAtIndex(int index, int digit)
{
int number = BeginNumber(digit) + index / digit; //计算出index对应的数字在哪个数中
int indexFromRight = digit - index % digit; //得出index所在的数字右边的个数(如1001,在370的7位置,indexFromRight表示7的右边还有几个数字)
//把所在的位置变成个位,然后对其求余返回得到结果
for (int i = 1; i < indexFromRight; i++)
number /= 10;
return number % 10;
}
/// <summary>
/// 计算某一位数开始的第一个数字是多少
/// </summary>
/// <param name="digit">位数</param>
/// <returns>开始的数字</returns>
private int BeginNumber(int digit)
{
//如果只有一位数,那么从0开始
if (digit == 1)
return 0;
//如果是二位数或者二位以上的数,从10的位数-1次方开始,比如二位数,从10(10的一次方)开始
return (int)Math.Pow(10, digit - 1);
}
/// <summary>
/// 计算某一位有多少个该位数(2位数有90个,10~99)
/// </summary>
/// <param name="digit">位数</param>
/// <returns>存在的数</returns>
private int CountOfDigit(int digit)
{
//如果只有一位数,那么只有10个数字可以选择
if (digit == 1)
return 10;
//如果是二位以上的数字,那么包含的数字有9×(位数-1)个数字
return 9 * (int)Math.Pow(10, digit - 1);
}
}
}