含重复字符的字符串全排列算法(思路+分析)
2012-08-12 13:07
288 查看
从昨天到现在一直在回顾字符串的全排列算法,之前简单地复习了不含重复字符的字符串全排列,所以这次想彻底解决该算法。关于不含重复字符的字符串全排列比较简单,直接用递归思路解决即可,简单代码如下:
但是上述方法在存在重复字符的情况下则失效。上述代码中方法1和方法2为简单地改进,希望可以解决含重复字符的字符串全排列。但是在上机运行后发现是行不通的。简单分析了下原因,则是因为这两种改进均不能完成整个解空间的搜索,所以会漏掉部分解,也可能有重复解!
所以现在要换一种思路,在查找一定资源的基础上,发现了如下的有效算法,可以很好地实现字符串的全排列,包括重复字符存在的情况。该算法的思想是:
首先对原字符串进行排序,然后顺序地从原字符中逐个地取字符复制到解空间中,如果某字符和其前一个字符相同,则只处理一次。
简单地将就是在解空间的位置上逐个放置不同的字符,直至全部字符复制完毕。
举例来讲,对于abb,在第一个位置上有a,b两种情况,a时,只有b,b顺序。b时,则有a,b;b,a两种顺序。算法结束。代码如下:
运行结果如下图所示:
当然,这种算法也存在着两个主要缺点:
1、额外增加了排序算法,耗时增加;
2、复制相当于使用了外部空间,空间使用增加。
template <class T> void permute(T list[],int k, int m) { int i; if (k==m) { for (i=0;i<=m;i++) cout<<list[i]; cout<<endl; } for (i=k;i<=m;i++) { //if (list[k]!=list[i]&&i!=k) //方法1:如果不同位置上的字符不相同,则进行交换 //{ // if ( IsSwap(list+i,list+m))//方法2:如果从该字符起,在区间[pBegin , pEnd)上没有重复字符,则进行交换,参考http://blog.csdn.net/hackbuteer1/article/details/7462447 // { lswap(list+k,list+i); permute(list,k+1,m); lswap(list+i,list+k); //} } //} }
template <class T> inline bool IsSwap(T* pBegin , T* pEnd) { T *p; for(p = pBegin ; p < pEnd ; p++) { if(*p == *pEnd) return false; } return true; }
但是上述方法在存在重复字符的情况下则失效。上述代码中方法1和方法2为简单地改进,希望可以解决含重复字符的字符串全排列。但是在上机运行后发现是行不通的。简单分析了下原因,则是因为这两种改进均不能完成整个解空间的搜索,所以会漏掉部分解,也可能有重复解!
所以现在要换一种思路,在查找一定资源的基础上,发现了如下的有效算法,可以很好地实现字符串的全排列,包括重复字符存在的情况。该算法的思想是:
首先对原字符串进行排序,然后顺序地从原字符中逐个地取字符复制到解空间中,如果某字符和其前一个字符相同,则只处理一次。
简单地将就是在解空间的位置上逐个放置不同的字符,直至全部字符复制完毕。
举例来讲,对于abb,在第一个位置上有a,b两种情况,a时,只有b,b顺序。b时,则有a,b;b,a两种顺序。算法结束。代码如下:
#define MAXBUFFERSIZE 100 using namespace std; void Permutation(char d[],char s[], int i, int l); void Sort(char s[]); int count = 0; void main() { char s[MAXBUFFERSIZE]; char d[MAXBUFFERSIZE]; // input source string// cout<<"Input source string:"<<endl; gets(s); // 排序,排列并输出// Sort(s); Permutation( d, s, 0, strlen(s)); return; } // 运用递归输出各种排列// void Permutation(char d[],char s[], int i, int n) { int j; char temp; for(j = 0; j < n; j ++) { if ( j>0 && s[j] == s[j - 1] ) //如果当前字符和前一个字符串相同,则跳过该字符// ; else if ( s[j] != '#' ) //如果标志为不为'#',即当前字符没有被复制// { d[i] = s[j]; //把源串的一个字符赋给目的串// temp = s[j]; s[j] = '#'; if(i == n - 1) { d = '\0'; cout<<setw(2)<<++::count<<":"; // 打印出其结果// cout<<d<<endl; } else Permutation( d, s, i + 1, n); // 递归调用// s[j] = temp; // 回溯// } } } // 冒泡排序// void Sort(char s[]) { int n = strlen(s); int i, j; char temp; for(i = 0; i < n - 1; i ++) for(j = i + 1; j < n; j ++) if(s[i] > s[j]) { temp = s[i]; s[i] = s[j]; s[j] = temp; } }
运行结果如下图所示:
当然,这种算法也存在着两个主要缺点:
1、额外增加了排序算法,耗时增加;
2、复制相当于使用了外部空间,空间使用增加。
相关文章推荐
- 字符串算法——有重复字符的数组或字符串全排列(Permutations II)
- 算法题---“查找重复字符并删除”解题思路分析
- 尾单词长度、1 3 9 27 81 实现1-121任意算法、去除重复字符并排序、拼音转数字、按要求分解字符串
- 【算法剖析】求字符串中无重复字符的最长字串
- 字符串的全排列问题(一)——无重复出现字符的排列
- 实现一个算法来判断一个字符串中的字符是否唯一(即没有重复).不能使用额外的数据结构。 (即只使用基本的数据结构)
- 人人都来写算法 之 移除字符串中重复的字符,时间复杂度要求O(n),空间复杂度O(1)
- 经典算法面试题目-设计算法移除字符串中重复的字符(1.3)
- 算法分析---删除字符串中出现次数最少的字符
- 字符串的排列(全排列,包含重复的字符)
- 经典算法面试题目-设计算法移除字符串中重复的字符(1.3)
- 从键盘输入一个由字母构成的字符串(不大于30个字符),要求从该串中取出3个不重复的字符,求所有不同的取法。如果字符串中没有取到3个不同的字符,则提示没有结果。对取出的字符要求按字母升序排列成串,对于不
- 字符串的排列和组合(不考虑字符重复的情况)
- 算法学习(java实现之字符串篇)·····判断字符串是否没有重复字符
- 对于一个字符串,请设计一个高效算法,找到第一次重复出现的字符。 给定一个字符串(不一定全为字母)A及它的长度n。请返回第一个重复出现的字符。保证字符串中有重复字符,字符串的长度小于等于500。
- 去除字符串中的重复字符,算法不使用额外缓冲。如abbc->abc
- 题目:剔除一个字符中重复的字符,然后按ASCII码值从小到大排列。 例如,输入:abbcccddeeeffgghh 输出:abcdefgh 注意:1、剔除是整个字符串中重复的字符,而不是连续的字符 2
- 设计一个算法移除字符串中的重复字符,并写出测试用例。
- 【常用算法思路分析系列】字符串高频题集
- java小算法—去除字符串重复字符