如何判断一个字符串是不是回文字符串以及字符串的排列组合问题

来源:互联网 发布:人工智能产业政策 编辑:程序博客网 时间:2024/05/16 03:12

所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba"。


题目:判断一个字符串是否为回文

解法:递归


递归的作用在于把问题的规模不断缩少,直到问题缩少到能简单地解决

问:如何缩少问题规模?

答:通过观察可以知道,一个回文字符串其中内部也是回文。所以,我们只需要以去掉两端的字符的形式一层层检查,每一次的检查都去掉了两个字符,这样就达到了缩少问题规模的目的。


新问题与原问题有着相同的形式

当去掉两端字符后的字符串,其产生的新问题同样是检查这个字符串是否回文。


递归的结束需要简单情景

1. 字符串长度可能会奇数或偶数:

  • 如果字符串长度是奇数,字符串会剩下最中间那位字符,但其不影响回文。当检查到长度为1的时候即代表此字符串是回文
  • 如果字符串长度是偶数,当两端的字符串两两比较检查后不会剩下字符。即检查到长度为0的时候即代表此字符串是回文

2. 如果检查到两端两个字符不相同。则说明此字符串不是回文,直接返回0,不需要继续检查



#include <iostream>#include <cstring>#include <cstdio>#include <string>using namespace std;int fun(int l, int r, string str, int len){if (0 == len || 1 == len)return 1;if (str[l] != str[r])return 0;return fun(l + 1, r - 1, str, len - 2);}int main(){string ss;while (getline(cin, ss)){cout << fun(0, ss.size() - 1, ss, ss.size()) << endl;;}system("pause");}


问题1 :输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符abc所能排列出来的所有字符串abcacbbacbcacabcba

    思路:这是个递归求解的问题。递归算法有四个特性:(1)必须有可达到的终止条件,否则程序将陷入死循环;(2)子问题在规模上比原问题小;(3)子问题可通过再次递归调用求解;(4)子问题的解应能组合成整个问题的解。

    对于字符串的排列问题。如果能生成n - 1个元素的全排列,就能生成n个元素的全排列。对于只有1个元素的集合,可以直接生成全排列。全排列的递归终止条件很明确,只有1个元素时。下面这个图很清楚的给出了递归的过程。


    参考代码:解法1通过Permutation_Solution1(str, 0, n); 解法2通过调用Permutation_Solution2(str, str)来求解问题。

[cpp] view plain copy
 print?
  1. //函数功能 : 求一个字符串某个区间内字符的全排列  
  2. //函数参数 : pStr为字符串,begin和end表示区间  
  3. //返回值 :   无  
  4. void Permutation_Solution1(char *pStr, int begin, int end)  
  5. {  
  6.     if(begin == end - 1) //只剩一个元素  
  7.     {  
  8.         for(int i = 0; i < end; i++) //打印  
  9.             cout<<pStr[i];  
  10.         cout<<endl;  
  11.     }  
  12.     else  
  13.     {  
  14.         for(int k = begin; k < end; k++)  
  15.         {  
  16.             swap(pStr[k], pStr[begin]); //交换两个字符  
  17.             Permutation_Solution1(pStr, begin + 1, end);  
  18.             swap(pStr[k],pStr[begin]);  //恢复  
  19.         }  
  20.     }  
  21. }  
  22.   
  23. //函数功能 : 求一个字符串某个区间内字符的全排列  
  24. //函数参数 : pStr为字符串,pBegin为开始位置  
  25. //返回值 :   无  
  26. void Permutation_Solution2(char *pStr, char *pBegin)  
  27. {  
  28.     if(*pBegin == '\0')  
  29.     {  
  30.         cout<<pStr<<endl;  
  31.     }  
  32.     else  
  33.     {  
  34.         char *pCh = pBegin;  
  35.         while(*pCh != '\0')  
  36.         {  
  37.             swap(*pBegin, *pCh);  
  38.             Permutation_Solution2(pStr, pBegin + 1);  
  39.             swap(*pBegin, *pCh);  
  40.             pCh++;  
  41.         }  
  42.     }  
  43. }  
  44. //提供的公共接口  
  45. void Permutation(char *pStr)  
  46. {  
  47.     Permutation_Solution1(pStr, 0, strlen(pStr));  
  48.     //Permutation_Solution2(pStr,pStr);  
  49. }  

    问题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。

[cpp] view plain copy
 print?
  1. //函数功能 : 从一个字符串中选m个元素  
  2. //函数参数 : pStr为字符串, m为选的元素个数, result为选中的  
  3. //返回值 :   无  
  4. void Combination_m(char *pStr, int m, vector<char> &result)  
  5. {  
  6.     if(pStr == NULL || (*pStr == '\0'&& m != 0))  
  7.         return;  
  8.     if(m == 0) //递归终止条件  
  9.     {  
  10.         for(unsigned i = 0; i < result.size(); i++)  
  11.             cout<<result[i];  
  12.         cout<<endl;  
  13.         return;  
  14.     }  
  15.     //选择这个元素  
  16.     result.push_back(*pStr);  
  17.     Combination_m(pStr + 1, m - 1, result);  
  18.     result.pop_back();  
  19.     //不选择这个元素  
  20.     Combination_m(pStr + 1, m, result);  
  21. }  
  22. //函数功能 : 求一个字符串的组合  
  23. //函数参数 : pStr为字符串  
  24. //返回值 :   无  
  25. void Combination(char *pStr)  
  26. {  
  27.     if(pStr == NULL || *pStr == '\0')  
  28.         return;  
  29.     int number = strlen(pStr);  
  30.     for(int i = 1; i <= number; i++)  
  31.     {  
  32.         vector<char> result;  
  33.         Combination_m(pStr, i, result);  
  34.     }  
  35. }  
     问题3:打靶问题。一个射击运动员打靶,靶一共有10环,连开10 枪打中90环的可能性有多少?

     思路:这道题的思路与字符串的组合很像,用递归解决。一次射击有11种可能,命中1环至10环,或脱靶。

     参考代码:

[cpp] view plain copy
 print?
  1. //函数功能 : 求解number次打中sum环的种数  
  2. //函数参数 : number为打靶次数,sum为需要命中的环数,result用来保存中间结果,total记录种数   
  3. //返回值 :   无  
  4. void ShootProblem_Solution1(int number, int sum, vector<int> &result, int *total)  
  5. {  
  6.     if(sum < 0 || number * 10 < sum) //加number * 10 < sum非常重要,它可以减少大量的递归,类似剪枝操作  
  7.         return;  
  8.     if(number == 1) //最后一枪  
  9.     {  
  10.         if(sum <= 10) //如果剩余环数小于10,只要最后一枪打sum环就可以了  
  11.         {  
  12.             for(unsigned i = 0; i < result.size(); i++)  
  13.                 cout<<result[i]<<' ';  
  14.             cout<<sum<<endl;  
  15.             (*total)++;  
  16.             return;  
  17.         }  
  18.         else  
  19.             return;  
  20.     }  
  21.     for(unsigned i = 0; i <= 10; i++) //命中0-10环  
  22.     {  
  23.         result.push_back(i);  
  24.         ShootProblem_Solution1(number-1, sum-i, result, total); //针对剩余环数递归求解  
  25.         result.pop_back();  
  26.     }  
  27. }  
  28. //提供的公共接口  
  29. void ShootProblem(int number, int sum)  
  30. {  
  31.     int total = 0;  
  32.     vector<int> result;  
  33.     ShootProblem_Solution1(number, sum, result, &total);  
  34.     cout<<"total nums = "<<total<<endl;  
  35. }  




阅读全文
0 0