字符串的全排列

题目描述

 输入一个字符串,打印出该字符串中字符的全排列。

解法一:递归实现

 从未打印字符中选择一个打印,递归打印剩余字符。

具体实现:将要打印的字符移动到剩余字符串的头部,递归至没有剩余字符时一起全部打印。
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 
#include 
#include 
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;
}

你可能感兴趣的:(《编程之法》学习笔记,string,C++,全排列,编程之法)