做题过程中经常有全排列问题,直接用 STL 中的 next_permutation 方法其实就可以了(需要 #include < algorithm >)。
#include <iostream>
#include <string>
#include <algorithm> // for "next_permutation"
using namespace std;
void Permutation(string str)
{
if (str.length() == 0) return;
// sort(str.begin(), str.end()); 想要全排列就先 sort 即可
while (next_permutation(str.begin(), str.end()))
cout << str << endl;
cout << "when finished, str = " << str << endl;
}
int main()
{
string str{ "123" };
Permutation(str);
return 0;
}
输出结果如下:
132
213
231
312
321
when finished, str = 123
可以看到结果是没有问题的,不过 最后一次虽然函数返回值是 false,str 还是被修改了。
到源代码中查看,如下,可以看到红色箭头指向位置导致当已经是最后一次全排列的时候,函数会把传入的参数前后掉个个儿。
同时可以看到这个函数的默认参数比较方法是 less<>(),也就是说,不会比较是否相同,如果传入字符串为 “122”,只会有122,212,221 三个排列。不会像 “123” 一样有 6 种。
next_permutation(str.begin(), str.end()) 用 lambda 表达式显示写出来比较函数,大概应该是 next_permutation(str.begin(), str.end(), [](const char& a, const char& b) { return a < b; }) 这样。
学习为主,自己写了一个 next_str 函数处理 string 数据,其实思路都是一样的。
bool next_str(string& str)
{
const int len = str.length();
if (len <= 1) return false;
int left = -1, right = -1;
// 从后往前,找到第一个降序位置 left, 如 "2431" 中的位置 0,即 '2'
for (int i = len - 1; i > 0; --i)
if (str[i] > str[i - 1])
{
left = i - 1;
break;
}
// 如果没有找到,则已经是最后一个 permutation,返回 false
if (left == -1) return false;
// 从后往前,找到第一个比 str[left] 大的位置 right, 如 "2431" 中的位置 2, 即 '3'
for (int i = len - 1; i > left; --i)
if (str[i] > str[left])
{
right = i;
break;
}
// 交换 left 和 right
swap(str[left], str[right]);
// 从 left + 1 到最后,排序
sort(str.begin() + left + 1, str.end());
return true;
}
“1234” 的结果为
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321
when finished, str = 4321
因为当完全降序的时候,直接返回 false,所以最后 str 保持完全降序结果。算法流程就是:
1、从后往前,找到第一个降序位置 left, 如 “2431” 中的位置 0,即 ‘2’
(如果没有找到,则已经是最后一个 permutation,返回 false)
2、从后往前,找到第一个比 str[left] 大的位置 right, 如 “2431” 中的位置 2, 即 ‘3’
3、交换 left 和 right 位置上的值
4、从 left + 1 到最后,排序
通过例子可以更好地理解:2431 -> 3124 -> 3142 。
计算 2431 的下一个排列的过程为:
1、从后往前,找到第一个将序位置,即 ‘2’ 的位置 0
2、从后往前,找到第一个比 ‘2’ 大的值 ‘3’ 的位置 2
3、交换 ‘2’ 和 ‘3’, 变成 3421
4、从位置 1 (0 + 1) 到最后,进行排序,变成 3124,即为结果。