求回文數算法


問題:

    求第N個回文數palindrome。

    一個正數如果順着和反過來都是一樣的(如13431,反過來也是13431),就稱為回文數。約束:

    回文數不能以0開頭

    回文數從1開始。

首先我們要寫一個算法求回文數。剛開始我想到用用字符串來存儲數,然后判斷原序和逆序是否相等。

 

void func1(char a[])
{
    printf("%d",strlen(a));
 
    char *p=a;
        char *q=a+strlen(a)-1;  
        bool flag=true;
        while(q>p)
        {
            if(*q!=*p)
            {
                flag=false;
                break;
            }
            q--;p++;
        }
        if(flag)
            printf("%s 是回文數\n",a);
        else
            printf("%s 不是回文數\n",a);
         

}
int main()
{
     
    char s[50];
    while(scanf("%s",s)!=0)
    {
      printf("%d",strlen(s));
       func1(s);
         
    }

 

注意,用strlen的時候只檢測什么時候到‘\0'位置,與sizeof無關,如果是sizeof的話char a[]做函數參數a會降級為指針

雖然這樣做可以,但還是有點小問題,如果輸入010,輸出回文。不滿足回文的定義。

回文數不能以0開頭

  一開始就思考使用循環:從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;
    }

 

全部代碼:

package com.icescut.classic.algorithm;
//數位指個位,十位,百位,千位。。。
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;
    }
}

說明:

    因為按規律計算,效率為O1,不論數量級多大,能馬上得到結果(不發生溢出情況下)。對比循環判斷回文數的方法,大大的改善了。

轉自:http://www.cnblogs.com/icescut/archive/2009/11/09/PalindromicNumber.html

 

 

 

 

缺8數、回文數的秘密

 人們把12345679叫做“缺8數”,這“缺8數”有許多讓人驚訝的特點,比如用9的倍數與它相乘,乘積竟會是由同一個數組成,人們把這叫做“清一色”。比如:

 

12345679*9=111111111

12345679*18=222222222

12345679*27=333333333

……

12345679*81=999999999

這些都是9的1倍至9的9倍的。

還有99、108、117至171。最后,得出的答案是:

12345679*99=1222222221

12345679*108=1333333332

12345679*117=1444444443

 。。。

12345679*171=2111111109

 

回文數

中文里,有回文詩句、對聯,如:"靈山大佛,佛大山靈","客上天然居,居然天上客"等等,都是美妙的符合正念倒念都一樣的回文句.

回文數則是有類似22、383、5445、12321,不論是從左向右順讀,還是從右向左倒讀,結果都是一樣的特征.許多數學家着迷於此。

回文數中存在無窮多個素數11,101,131,151,191……。除了11以外,所有回文素數的位數都是奇數。道理很簡單:如果一個回文素數的位數是偶數,則它的奇數位上的數字和與偶數位上的數字和必然相等;根據數的整除性理論,容易判斷這樣的數肯定能被11整除,所以它就不可能是素數。附整除原理11整除的特征。

能被11整除的數的特征
把一個數由右邊向左邊數,將奇位上的數字與偶位上的數字分別加起來,再求它們的差,如果這個差是11的倍數(包括0),那么,原來這個數就一定能被11整除.
例如:判斷491678能不能被11整除.
—→奇位數字的和9+6+8=23

—→偶位數位的和4+1+7=12 23-12=11
因此,491678能被11整除.
這種方法叫"奇偶位差法".
除上述方法外,還可以用割減法進行判斷.即:從一個數里減去11的10倍,20倍,30倍……到余下一個100以內的數為止.如果余數能被11整除,那么,原來這個數就一定能被11整除.
又如:判斷583能不能被11整除.
用583減去11的50倍(583-11×50=33)余數是33, 33能被11整除,583也一定能被11整除.

 

 )。

人們借助電子計算機發現,在完全平方數、完全立方數中的回文數,其比例要比一般自然數中回文數所占的比例大得多。例如11^2=121,22^2=484,7^3=343,11^3=1331……都是回文數。

人們迄今未能找到四次方、五次方,以及更高次冪的回文素數。於是數學家們猜想:不存在nk(k≥4;n、k均是自然數)形式的回文數。

 

在電子計算器的實踐中,還發現了一樁趣事:任何一個自然數與它的倒序數相加,所得的和再與和的倒序數相加,……如此反復進行下去,經過有限次步驟后,最后必定能得到一個回文數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM