問題1:輸入一個字符串,打印該字符串中字符的全部排列,例如輸入字符串abc,則輸出由字符a、b、c所能排列出來的全部字符串abc、acb、bac、bca、cab和cba。 算法
思路:這是個遞歸求解的問題。遞歸算法的四個特性:(1)必須有可達到的終止條件,不然程序將陷入死循環;(2)子問題在規模上比原問題小;(3)子問題可經過再次遞歸調用求解;(4)子問題的解能組合成整個問題的解。 函數
對於字符串的排列問題。若是能生成n - 1個元素的全排列,就能生成n個元素的全排列。對於只有1個元素的集合,能夠直接生成全排列。全排列的遞歸終止條件很明確,只有1個元素時。下面這個圖很清楚的給出了遞歸的過程。 spa
//函數功能:求一個字符串某個區間內字符的全排列 //函數參數:pStr爲字符串,begin和end表示區間 //返回值:無 void Permutation_Solution1(char *pStr,int begin,int end) { if(begin == end-1)//只剩一個元素 { for(int i=0;i<end;i++)//打印 cout<<pStr[i]; cout<<endl; } else { for(int k=begin;k<end;k++) { swap(pStr[k],pStr[begin]);//交換兩個字符 Permutation_Solution1(pStr,begin-1,end); swap(pStr[k],pStr[begin]);//恢復 } } } //函數功能:求一個字符串某個區間內字符的全排列 //函數參數:pStr爲字符串,pBegin爲開始位置 //返回值:無 void Permutation_Solution2(char *pStr,char *pBegin) { if(*pBegin == '\0') { cout<<pStr<<endl; } else { char *pCh = pBegin; while(*pCh != '\0') { swap(*pBegin,*pCh); Permutation_Solution2(pStr,pBegin+1); swap(*pBegin,*pCh); pCh++; } } } //提供的公共接口 void Permutation(char *pStr) { Permutation_Solution1(pStr,0,strlen(pStr)); //Permutation_Solution2(pStr,pStr));???? }問題2:輸入一個字符串,輸出該字符串中字符的全部組合。舉個例子,若是輸入abc,它的組合有a、b、c、ab、ac、bc、abc。
思路:一樣是用遞歸求解。能夠考慮求長度爲n的字符串中m個字符的組合,設爲C(n,m)。原問題的解即爲C(n, 1), C(n, 2),...C(n, n)的總和。對於求C(n, m),從第一個字符開始掃描,每一個字符有兩種狀況,要麼被選中,要麼不被選中,若是被選中,遞歸求解C(n-1, m-1)。若是未被選中,遞歸求解C(n-1, m)。無論哪一種方式,n的值都會減小,遞歸的終止條件n=0或m=0。 code
//函數功能 : 從一個字符串中選m個元素 //函數參數 : pStr爲字符串, m爲選的元素個數, result爲選中的 //返回值 : 無 void Combination_m(char *pStr, int m, vector<char> &result) { if(pStr == NULL || (*pStr == '\0'&& m != 0)) return; if(m == 0) //遞歸終止條件 { for(unsigned i = 0; i < result.size(); i++) cout<<result[i]; cout<<endl; return; } //選擇這個元素 result.push_back(*pStr); Combination_m(pStr + 1, m - 1, result); result.pop_back(); //不選擇這個元素 Combination_m(pStr + 1, m, result); } //函數功能 : 求一個字符串的組合 //函數參數 : pStr爲字符串 //返回值 : 無 void Combination(char *pStr) { if(pStr == NULL || *pStr == '\0') return; int number = strlen(pStr); for(int i = 1; i <= number; i++) { vector<char> result; Combination_m(pStr, i, result); } }問題3:打靶問題。一個射擊運動員打靶,靶一共有10環,連開10 槍打中90環的可能性有多少?
思路:這道題的思路與字符串的組合很像,用遞歸解決。一次射擊有11種可能,命中1環至10環,或脫靶。 遞歸
//函數功能 : 求解number次打中sum環的種數 //函數參數 : number爲打靶次數,sum爲須要命中的環數,result用來保存中間結果,total記錄種數 //返回值 : 無 void ShootProblem_Solution1(int number, int sum, vector<int> &result, int *total) { if(sum < 0 || number * 10 < sum) //加number * 10 < sum很是重要,它能夠減小大量的遞歸,相似剪枝操做 return; if(number == 1) //最後一槍 { if(sum <= 10) //若是剩餘環數小於10,只要最後一槍打sum環就能夠了 { for(unsigned i = 0; i < result.size(); i++) cout<<result[i]<<' '; cout<<sum<<endl; (*total)++; return; } else return; } for(unsigned i = 0; i <= 10; i++) //命中0-10環 { result.push_back(i); ShootProblem_Solution1(number-1, sum-i, result, total); //針對剩餘環數遞歸求解 result.pop_back(); } } //提供的公共接口 void ShootProblem(int number, int sum) { int total = 0; vector<int> result; ShootProblem_Solution1(number, sum, result, &total); cout<<"total nums = "<<total<<endl; }