poj1019

本文问题分析参考http://blog.csdn.net/lyy289065406/article/details/6648504

大致题意:

有一串数字串,其规律为

1 12 123 1234 12345 123456 1234567 12345678 123456789 12345678910 1234567891011 123456789101112······k

输入位置n,计算这一串数字第n位是什么数字,注意是数字,不是数!例如12345678910的第10位是1,而不是10,第11位是0,也不是10。总之多位的数在序列中要被拆分为几位数字,一个数字对应一位。

 

解题思路:

首先建议数学底子不好的同学,暂时放一放这题,太过技巧性了,连理解都很困难

 

模拟分组,把1看做第1组,12看做第2组,123看做第3组……那么第i组就是存放数字序列为 [1,i]的正整数,但第i组的长度不一定是i

 

已知输入查找第n个位的n的范围为(1 ≤ n ≤ 2147483647),那么至少要有31268个组才能使得数字序列达到有第2147483647位

 

注意:2147483647刚好是int的正整数最大极限值( ),所以对于n用int定义就足矣。但是s[31268]存在超过2147483647的位数,因此要用unsigned 或long 之类的去定义s[]

 

详细的解题思路请参照程序的注释。

其中数学难点有2:

(int)log10((double)i)+1

(i-1)/(int)pow((double)10,len-pos)%10

非常技巧性的处理手法,其意义已在程序中标明


//* @author:

//方法一:


/**
 * 有一串数字串,其规律为:11212312341234512345612345671234567812345678912345678910123456789101112345678910······


      输入位置,输出对应位置的数字,
      如:输入8,输出2;输入:56,输出0,
      注意:两位数字、三位数字对应位都是分开的,难度在这里,输入范围是
   
  其主要算法如下:
  父数字串------>>子数字串-------->>最简数字串
 */
public class Main {


/**
*  求数 n 的位数,如:
*  12的位数为2,100的位数为3,,5的位数为1
* @param n
* @return
*/

public static int getWeiShu(int n) {
int weiShu = 0;
while (n != 0) {
n = n / 10;
weiShu++;
}
return weiShu;
}


public static int location(int i) {
// i - 所求序数
// ans - 所求位的数字
// j - 递推定位串
// base - 记录每个串递增的位数
// sum - 记录串的总位数 、 用作计数


int ans;
int j = 1, base, sum = 1;

while (i >= sum) {//如果所求的位置大于数字串的总位数
//将所求的序数减去某一个串的总位数
i -= sum;

j++; // j 记载 下一个串 到哪个数字串了 -- 12...j

//获取某一个数字串的位数
base = getWeiShu(j);
// 该串比上一个串多的字符数 - j 的位数
//其实是某一个数字串的位数如112123,sum在这里表示的是数字串1
//或数字串12,或数字串123的位数
sum += base; // 该串的字符总数
}

// 出口:i >= 0
/**
* 当序数i恰好到某一个数字串就结束了
*/
if (i == 0) {
ans = (j - 1) % 10;
return ans;
}


/**
* 以上代码应该是实现了将i定位到某一个数字串的功能,
* 例如,从112123123412345中找出了i在12345中

*/

sum = 1; // 从串(1...j) 中第一个数开始找
base = 1; // 串中第一个数的位数是 1
while (i >= base) // 求 1...j 串中第 i 个数字
{
i -= base;
sum++;

//base用来记录当前遍历到数组的位数
base = getWeiShu(sum); // sum 的位数
}



/**
* if语句主要用于处理这是已经是没有字数字串的情况
* 即,在12345中找到了某一个数字,或1,或2,或3,
*/
if (i == 0) {
ans = (sum - 1) % 10;
return ans;
}


/**
* 以下代码主要处理:
* 在小字符串中如123456789101112131415中
* 的12中确定到底是哪一个数字

* 对于以下求i的算法,理解如下:


*对于123456789(不可能为1234567891011···,此时的数字串已经为最简数字串,不可能在包含子数字串),
*加入我们要取5,我们通常习惯于%10,-----(但是%10时,我们取的是个位)--------->>所以得把
*5以后的数字都去掉,-----(这时我们习惯采取/10操作)-------->>/10的次数由getWeiShu(sum)-i来决定
*/
j = getWeiShu(sum) - i;
while (j-- > 0) // ans is the ith number of (sum)
{
sum /= 10;
}
ans = sum % 10;
return ans;
}


public static void main(String[] args) {


java.util.Scanner input = new java.util.Scanner(System.in);
int t = input.nextInt(); // test number,测试用例的个数


while (t-- > 0) {
//要求位置的数字
int i = input.nextInt();
System.out.println(location(i));
}
}


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅气的东哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值