经典算法之求第N个回文数

问题:

    求第N个回文数。

    一个正数如果顺着和反过来都是一样的(如13431,反过来也是13431),就称为回文数。约束:

    回文数不能以0开头

    回文数从1开始。

 

思路:

    许多朋友(包括我自己)一开始就思考使用循环:从1开始,判断该数是否是回文数,然后用一

个计数器记下回文数,一直到计数器得到N,返回第N个回文数。比较常用的是以下这种方法来判断是

否回文数:

static boolean isPN(int num) {
    
int o = num;
    
int tmp = 0;
    
//使用循环把数字顺序反转
    while(num != 0) {
        tmp 
*= 10;
        tmp 
+= num % 10;
        num 
/= 10;
    }
    
//如果原始数与反转后的数相等则返回true
    if(tmp == o) 
        
return true;
    
return false;
}

 

    这种思路的确可得到正确结果,但随着用来测试的N的增大,效率的问题就浮现了。因为是一重

循环,效率是O(n)。所以当N非常大时,所花的时间还是十分大的。

   另一种思路:

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

    1位回文数: 9个

    2位回文数: 9个

    3位回文数: 90个

    4位回文数: 90个

    5位回文数: 900个

    6位回文数: 900个

    …

    我们看到9、90、900,是不是很有规律,那是什么原因?很简单,我们把回文数拆开两半

[123321]来看。两半的变化一样的,那我们只算其中一半就行了。首位不能是0,所以左半最小为

100,最大为999,共有999-100=900个,如此类推。

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

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

从9个变为90个。

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

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

 

核心代码:

static long find(int index) {
        
int count = 0;            
        
int number = 9;                        //记录数位上的回文数,如个位回文数为9
        int w = 0;                            //记录数位
        
        
long half;                            //保存回文数的左半边的结果
        long h = 1;                            //回文数的左半边的起始基数
        long res;                            //结果
        
        
while(true) {
            
if(w > 0 && w%2 == 0) {            //每进两个数位,回文数乘以10
                number *= 10;
            }
            w
++;                            //数位加一
            if(count + number > index)        //回文数大于查找的回数,跳出
                break;
                
            count 
+= number;                //回文数加上当前数位上的回文数
        }
        
        index 
-= count;                        //在当前数位上的位置。如w=5,index=50,则万位上的第50个回文数是我们所求
        
        
for(int i = 0; i < (w-1/ 2; i++) {    //求回文数的左半边的基数,如回文数在万位上,则为100
            h *= 10;
        }
        
        half 
= h + index;                        //回文数的左半边,如100 + 50 = 150
        
        res 
= half;
        
        
if(w%2 != 0)                            //如果为奇数,则中间那个数不必算入右半边了!
            half /=10;
            
        
while(half != 0) {                        //拼接回文数
            res = res *10 + half % 10;
            half 
/= 10;
        }
        
        
return res;
    }

 

全部代码:

Code

 

说明:

    因为按规律计算,效率为O1,不论数量级多大,能马上得到结果(不发生溢出情况下)。对比循环判断回文数的方法,大大的改善了。

posted @ 2009-11-09 09:08  小冰  阅读(6426)  评论(0编辑  收藏  举报