這是一道在線編程的題目,題目詳情:java
迴文字符串是指從左到右和從右到左相同的字符串,現給定一個僅由小寫字母組成的字符串,你能夠把它的字母從新排列,以造成不一樣的迴文字符串。c++
輸入:非空僅由小寫字母組成的字符串,長度不超過100;算法
輸出:能組成的全部迴文串的個數(由於結果可能很是大,輸出對1000000007取餘數的結果)。編程
例如:輸入"aabb" 輸出爲2(由於「aabb」對應的全部迴文字符串有2個:abba和baab)數組
函數頭部 c: int palindrome(const char *s); c++ int palindrome(const string &s); java public static int palindrome(String s) ; xss
個人解題思路函數
根據迴文字符串的特色,能夠知道,一個字符串若是是迴文字符串,那麼字符串須要知足的條件:字符串中每一個字母的個數必須是偶數,或者整個字符串只有一個字母的個數是奇數!好比串"aabbccccdd"即每一個字母個數均爲偶數,又如「aaabbcc」,只有一個字母a的個數是奇數,獲得解題方法:測試
舉個例子會更加清晰,好比字符串「aaabbccccdd」, a :3個, b:2個 , c:4個, d:2個 ,字符串長度爲11,那麼按公式來算就是ui
result = (11/2)! / 【(a/2)! * (b/2)! * (c/2)! * (d/2)! 】= 5! / (1! * 1! * 2! * 1!) = 120 / 2 = 60,這個方法是採用數學裏面的排列組合的知識,應該是高中學的!spa
有學過排列組合的人應該不難想到這種解題方法,可是公式中使用了大量的階乘,要知道階乘比指數增加更快更恐怖,int,long等類型的變量是沒法存儲那麼大的數字的,好比20的階乘是243 2902 0081 7664 0000,程序可能會用到50的階乘,各個類型的範圍以下:
unsigned int :0~4294967295
int :2147483648~2147483647 (10位)
unsigned long :0~4294967295
long : 2147483648~2147483647
long long的最大值:9223372036854775807 (19位)
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615 (20位)
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
正由於數據如此龐大,題目纔會提出對1000000007取模的要求,我嘗試了不少方法,試圖避免溢出的狀況,最後獲得一個比較合適的方法,既然數值有可能溢出,那麼咱們能夠採用化整爲零的方法,不直接計算分子中的(Lenth/2)!,將其認爲兩步走,
第一步,在作 (Lenth/2)!的同時( sum存儲結果,sum = sum * k,k = 1,2,3 ……Lenth/2),對(arr[ n ]/2)! 作除法,根據數學的常識,存在k指的sum能被(arr[ n ]/2)! 整除,直到(arr[ n ]/2)! 整除結束,即n = 25,記下此時的 sum 和 k;
第二步,繼續作(Lenth/2)!,開始位置爲 iter= k+ 1,result = sum(result即迴文字符串的個數),循環體爲result = (result * iter) % 1000000007; iter = k+1,k+2,……Lenth/2; 循環結束時獲得result的值,改值就是迴文字符串的個數!
注:再囉嗦一點,來解釋一下循環體的內容result = (result * iter) % 1000000007,若是在循環體中不對1000000007取餘,極可能會出現溢出的狀況,其數學原理爲:對於整數a ,M ,r有 a % M = r, 那麼 存在k,使得 a = kM + r,兩邊同時乘以n,獲得na = knM + nr, 因此有(na) % M = (nr) % M
以上即是我對這個題目的理解,下面將貼出個人程序的關鍵算法:
1 for(iter = 1; iter <= len/2; iter++) 2 { 3 MUL = MUL * iter; 4 while((arr[iterM] ==0 || arr[iterM] == 1) && iterM <26 ) 5 { 6 iterM++; 7 } 8 if(iterM < 26 && MUL % arr[iterM] == 0) 9 {10 MUL = MUL / arr[iterM];11 iterM++;12 }13 if(iterM >= 26)14 {15 death = iter ;16 result = MUL;17 break;18 }19 }20 for(iter = death + 1; iter <= len/2 ; iter++)21 {22 result = (result * iter) % 1000000007;23 }
View Code
MUL初值爲1,數組arr[26]中存儲的數值不是每一個字母的個數,而是(字母個數/2)的階乘,對,想必您也考慮到了,這裏可能會出現溢出的狀況,若是極端一點,字符串中存在一個字母的個數超過了50,算一下25的階乘,那麼這個算法就會溢出了,可是這種狀況好像也能夠特殊處理,我暫時還沒想到比較好的辦法,但願在這獲得大神的指教!
個人程序最終順利經過了在線編程系統的檢測,而且得到了相應的10個積分!下面羅列一些正確的測試用例,供你們使用!我沒有貼出完整代碼,須要的能夠留下郵箱地址!
用例1: s = 「xvwsxafqkcawfchxggvsxkq」 result = 19958400
用例2: s = 「hqaymehhrsfuqrpahrimsxftuxqrpsejouuehaqtsryxjhearxmogmi」 result = 676517829
用例3: s = 「zsmjajrycysuqjvyyraqvoyggmjgsuiyvclurvmygoivmsurgxsyyblvbgxsszlsly」 result = 493584849
用例4: s = 「btxgnhdjscrqkqvwzrhtqlekxrgettfvtzcfhtzlhqckkdkntwwrotzzfskddocobfdrkvqozkrxoqqjxcvdcqwo」 result = 376760527