問題:
求第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; } }
說明:
因為按規律計算,效率為O(1),不論數量級多大,能馬上得到結果(不發生溢出情況下)。對比循環判斷回文數的方法,大大的改善了。
轉自: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均是自然數)形式的回文數。
在電子計算器的實踐中,還發現了一樁趣事:任何一個自然數與它的倒序數相加,所得的和再與和的倒序數相加,……如此反復進行下去,經過有限次步驟后,最后必定能得到一個回文數。