回文数的一点点讨论【转】

问题:

    将所有回文数从小到大排列,求第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+1=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;
    }

全部代码:

public class PalindromicNumber {
    public static void main(String[] args) {
        int input = Integer.parseInt(args[0]);
        long res = find(input);
        System.out.println("res:" + res);
        
    }
    
    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;
    }
}
原文地址:https://www.cnblogs.com/Lee-geeker/p/3235328.html