数字序列中某一位的数字

题目描述

        数字以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);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33575542/article/details/80910141