字符串的全排列
写在前面:本文章为根据七月算法的讲解后的学习笔记与心得。
问题描述
给定一个字符串S[0…N-1],设计算法枚举S的全排列。
1.递归算法
思路:
举个栗子:求字符串s="1234"的全排列,有以下4类情况:
1 -(234);表示以1开头,234做全排列,具体怎么做,先不管(以下皆用此表示方法)
2-(134);表示以2开头,134做全排列
3-(214);表示以3开头,214做全排列
4-(123);表示以4开头,123做全排列
这四种情况合起来,就是1234的全排列,没毛病吧。
同理:以情况一内部为例:234做全排列
又有以下三种情况:
2-(34)
3-(24)
4-(32)
依次递归,规模逐渐减小,直到只剩最后一个字符时,直接输出整个串就好了,这也就是递归的出口。
那么问题来了,
1.如何实现以2,或者3,4开头呢?
答案是,将他们所在的位置,和首位字符进行交换就可以了鸭;
即,2原来在s[1],我们只需交换s[0]与s[1]即可;同理,3开头的话,交换s[0]与s[2]。
2.如何才能保证不重复不遗漏呢?
答案是,保证递归前字符串的顺序不变,例如1 -(234)结束后,要将字符串回到1234的顺序,才开始做2-(134),同理,在2 -(234)结束后,要将字符串回到1234的顺序,才开始做3-(134);
为啥呢?
因为每次,换下一个字符开头时,我们要进行交换,如果交换了但不恢复原位的话,那么原来的位置就可能不是原来的字符了。
这样就会造成重复或者遗漏;
直接看代码:
#include <iostream>
using namespace std;
///将字符串s,从from到to,做全排列
void FullPermutation(char*s, int from, int to) {
if (from == to) {
//递归出口,只剩最后一个字符了,按当前顺序输出字符
for (int i = 0; i <= from; i++) {
cout << s[i];
}
cout << endl;
return;
}
for (int i = from; i <= to; i++) {
swap(s[i], s[from]);//交换,即更改以另一个字符开头
FullPermutation(s, from + 1, to);//让下一位到结尾做全排列
swap(s[i], s[from]);//复位,很重要!!
}
}
int main() {
char s[500]; int m &#