字符排列问题
问题描述:对于输入的字符,输出所有不同的排列方式和总数,字符运行重复。
问题分析:
1) 若字符不允许重复时,全排列实现方法如下:
- 全排列最右边的n-1个字母;
- 轮换所有n个字母至第一位。
实现全排列最右边的n-1个字母跟全排列n个字母的方法一样,只是规模变小了,
所以可以采用递归的方式。
递归实现如下:
void backtrack(string s,int n,int k) { if(k==n-1) { cout<<s<<endl; return; } for(int i=k;i<n;i++) { swap(s[i],s[k]); backtrack(s,n,k+1); swap(s[i],s[k]); } }
2) 若字符重复,需排除重复的情况进入递归。
- 字符串为:”aab”,排除重复的情况就是与下标为k的字母相同的情形
即:s[i] == s[k]
- 字符串为:”abbc”,虽然这时没有不存在与下标为k的字母相同,但是
若swap(s[0], s[1]),即得到:”babc”
若swap(s[0], s[2]),即得到:”babc”,而这种情况是包含在上一种
情况(”babc”)中的全排列情形中的,所有重复排列了。这时解决方法
就是当s[j]前存在与s[j]相同的字符时,则当前的情形排除进入递归,因
为前面的字符已经包含了当前的情况。
综合上面两种情况,本题的实现代码如下:
void backtrack(string s,int n,int k) { if(k==n-1) { cout<<s<<endl; sum++; return; } for(int i=k;i<n;i++) { bool falg=1; for(int j=k;j<i;j++) { if(s[i]==s[j]) { falg=0; break; } } if(falg) { swap(s[i],s[k]); backtrack(s,n,k+1); swap(s[i],s[k]); } } }