题目描述
输入一个字符串,打印出该字符串中字符的全排列。
解法一:递归实现
从未打印字符中选择一个打印,递归打印剩余字符。
具体实现:将要打印的字符移动到剩余字符串的头部,递归至没有剩余字符时一起全部打印。
C++代码:
void permutation(string &str, int start)
{
if (start == str.size()) {
cout << str << endl;
return;
}
permutation(str, start + 1); // i = start
for (int i = start + 1; i < str.size(); ++i) {
if (str[i] != str[start]) { // skip duplicate string
swap(str[i], str[start]);
permutation(str, start + 1);
swap(str[i], str[start]);
}
}
}
void calcAllPermutation_1(string str)
{
if (str.size() == 0) {
return;
}
// formalize the interface
permutation(str, 0);
}
解法二:字典序排列
先对原字符串进行排序;循环打印输出字符串在字典序中的下一个排列。
算法核心为”寻找下一个字典序排列”:
1. 字符串从左到右,字符的有效值依次降低。类似于整数的有效位;
2. 找到值可以提升的最低有效位。即从最右边开始,找出第一个有这样的性质的字符:通过交换这个字符与其后的某个字符,得到的新字符串的字典序在原先字符串之后。 比如"adfecb",可以得到值提升的为'd',而'f'、'e'等字符,他们后面的字符都比他们小;
3. 提升2中找到的字符值,即与该字符后面最小的大于该字符的字符交换。比如"abfecb",结合2中分析交换'd'与'e',得到"aefdcb";
4. 提升的字符后面需要重新排序调整为局部最低字典序。即由"aefdcb"得到"aebcdf"。经过3、4两步后得到"adfecb"的下一个字典序排列为"aebcdf"。
C++代码:
bool nextPermutation(string &str)
{
if (str.size() <= 1) {
return false;
}
// fint the least significant one that can promote
int cur = str.size() - 2;
while (cur >= 0 && str[cur] >= str[cur + 1]) {
--cur;
}
if (cur < 0) {
return false;
}
// find the min one larger than str[cur]
int min = str.size() - 1;
while (str[min] <= str[cur]) {
--min;
}
swap(str[cur], str[min]);
// reverse the postfix substring from position i+1
int left = cur + 1, right = str.size() - 1;
while (left < right) {
swap(str[left], str[right]);
++left;
--right;
}
return true;
}
void calcAllPermutation_2(string str)
{
if (str.size() == 0) {
return;
}
sort(str.begin(), str.end()); // sort the string by alphabatical order
do {
cout << str << endl;
} while (nextPermutation(str)); // calculate the next string in lexicographical order
}
完整测试代码:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
void permutation(string &str, int start)
{
if (start == str.size()) {
cout << str << endl;
return;
}
permutation(str, start + 1); // i = start
for (int i = start + 1; i < str.size(); ++i) {
if (str[i] != str[start]) { // skip duplicate string
swap(str[i], str[start]);
permutation(str, start + 1);
swap(str[i], str[start]);
}
}
}
void calcAllPermutation_1(string str)
{
if (str.size() == 0) {
return;
}
// formalize the interface
permutation(str, 0);
}
bool nextPermutation(string &str)
{
if (str.size() <= 1) {
return false;
}
// fint the least significant one that can promote
int cur = str.size() - 2;
while (cur >= 0 && str[cur] >= str[cur + 1]) {
--cur;
}
if (cur < 0) {
return false;
}
// find the min one larger than str[cur]
int min = str.size() - 1;
while (str[min] <= str[cur]) {
--min;
}
swap(str[cur], str[min]);
// reverse the postfix substring from position i+1
int left = cur + 1, right = str.size() - 1;
while (left < right) {
swap(str[left], str[right]);
++left;
--right;
}
return true;
}
void calcAllPermutation_2(string str)
{
if (str.size() == 0) {
return;
}
sort(str.begin(), str.end()); // sort the string by alphabatical order
do {
cout << str << endl;
} while (nextPermutation(str)); // calculate the next string in lexicographical order
}
int main()
{
string str = "aabc";
calcAllPermutation_2(str);
return 0;
}