迴文字符串

 

這是一道在線編程的題目,題目詳情: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的個數是奇數,獲得解題方法:測試

  • 計算字符串的長度Lenth,統計每一個字母的長度,存入數組arr[26]中,下標與字母的ASCII碼相對應
  • 迴文字符串的個數result =  (Lenth / 2)! / ∏  (arr[ n ]/2)!  ,n = 0,1,2,3 ……,25,即26個字母

  舉個例子會更加清晰,好比字符串「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

相關文章
相關標籤/搜索