Chinaunix首页 | 论坛 | 博客
  • 博客访问: 104982
  • 博文数量: 18
  • 博客积分: 226
  • 博客等级: 二等列兵
  • 技术积分: 183
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-24 18:31
文章分类

全部博文(18)

文章存档

2013年(9)

2012年(7)

2011年(2)

我的朋友

分类: C/C++

2013-08-20 16:07:54

    一个正数如果顺着和反过来都是一样的(如13431,反过来也是13431),就称为回文数。约束:回文数不能以0开头 最小回文数是1。

思路1:

    许多朋友(包括我自己)一开始就思考使用循环:从1开始,判断该数是否是回文数,然后用一个计数器记下回文数,一直到计数器得到N,返回第N个回文数。比较常用的是以下这种方法来判断是否回文数:

点击(此处)折叠或打开

  1. static boolean isPN(int num)
  2. {
  3.     int o = num;
  4.     int tmp = 0;
  5.     //使用循环把数字顺序反转
  6.     while(num != 0)
  7.     {
  8.         tmp *= 10;
  9.         tmp += num % 10;
  10.         num /= 10;
  11.     }

  12.     //如果原始数与反转后的数相等则返回true
  13.     if(tmp == o)
  14.         return true;
  15.     return false;
  16. }

这种思路的确可得到正确结果,但随着用来测试的N的增大,效率的问题就浮现了。因为是一重 环,效率是O(n)。所以当N非常大时,所花的时间还是十分大的。

思路2:

回文数的个数其实是有规律的。如:

1位回文数: 9个

2位回文数: 9个

3位回文数: 90个

4位回文数: 90个

5位回文数: 900个

6位回文数: 900个

我们看到9、90、900,是不是很有规律,那是什么原因?很简单,我们把回文数拆开两半 [123321]来看。两半的变化一样的,那我们只算其中一半就行了。首位不能是0,所以左半最小为 100,最大为999,共有999-100+1=900个,如此类推。

所以我们可以基于以下原则:

1、 回文数的数位每增长2,回文数的个数为原来的10倍。如从个位回文数到百位回文数,个数 从9个变为90个。

2、 个位回文数的个数是9,1、2、3、…、9。

总之理解原理后一切好办,步骤就偷懒不写了,看代码吧!

核心代码:

点击(此处)折叠或打开

  1. static long find(int index)
  2. {
  3.     int count = 0;
  4.     int number = 9; //记录数位上的回文数,如个位回文数为9
  5.     int w = 0; //记录数位

  6.     long half; //保存回文数的左半边的结果
  7.     long h = 1; //回文数的左半边的起始基数
  8.     long res; //结果

  9.     while(true)
  10.     {
  11.         if(w > 0 && w%2 == 0)
  12.         { //每进两个数位,回文数乘以10
  13.             number *= 10;
  14.         }
  15.         w++; //数位加一
  16.         if(count + number > index) //回文数大于查找的回数,跳出
  17.             break;

  18.         count += number; //回文数加上当前数位上的回文数
  19.     }

  20.     index -= count; //在当前数位上的位置。如w=5,index=50,则万位上的第50个回文数是我们所求

  21.     for(int i = 0; i < (w-1) / 2; i++)
  22.     { //求回文数的左半边的基数,如回文数在万位上,则为100
  23.         h *= 10;
  24.     }

  25.     half = h + index; //回文数的左半边,如100 + 50 = 150

  26.     res = half;

  27.     if(w%2 != 0) //如果为奇数,则中间那个数不必算入右半边了!
  28.         half /=10;

  29.     while(half != 0)
  30.     { //拼接回文数
  31.         res = res *10 + half % 10;
  32.         half /= 10;
  33.     }
  34.     return res;
  35. }

本文思想转自
阅读(1781) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~