C++ STL next_permutation

  做题过程中经常有全排列问题,直接用 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,即为结果。

猜你喜欢

转载自blog.csdn.net/Bob__yuan/article/details/89043565