TA的每日心情  | 开心 2021-3-12 23:18 | 
|---|
 
  签到天数: 2 天 [LV.1]初来乍到  
 | 
 
| 
 
 问题:     将所有回文数从小到大排列,求第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;
 
 -     }
 
 - }
 
 
  复制代码      
      
      
        
        
 
         
        
 
         
        
      
     
 
   
 
 
源码下载:http://www.java3z.com/cwbwebhome/dir1/dir5/PalindromicNumber.zi |   
 
 
 
 |