在了解next_permutation算法是怎么一个过程之前,先来分析下“下一个排列”的性质。
假定现有字符串(A)x(B),它的下一个排列是:(A)y(B’),其中A、B和B’是“字符串”(可能为空),x和y是“字符”,前缀相同,都是A,且一定有y > x。
那么,为使下一个排列字典顺序尽可能小,必有:
- A尽可能长
- y尽可能小
- B’里的字符按由小到大递增排列
现在的问题是:找到x和y。怎么找到呢?咱们来看一个例子。
比如说,现在我们要找21543的下一个排列,我们可以从左至右逐个扫描每个数,看哪个能增大(至于如何判定能增大,是根据如果一个数右面有比它大的数存在,那么这个数就能增大),我们可以看到能增大的数是:x = 1。
而1应该增大到多少?1能增大到它右面比它大的那一系列数中最小的那个数,即:y = 3,故此时21543的下一个排列应该变为23xxx,显然 xxx(对应之前的B’)应由小到大排,于是我们最终找到23145刚好比21543大。
由这个例子可以得出next_permutation算法流程为:
- 定义
- 升序:相邻两个位置ai < ai+1,ai 称作该升序的首位
- 步骤(二找、一交换、一翻转)
- 找到排列中最后(最右)一个升序的首位位置i,x = ai
- 找到排列中第i位右边最后一个比ai 大的位置j,y = aj
- 交换x,y
- 把第(i + 1)位到最后的部分翻转
还是拿上面的21543举例,那么,应用next_permutation算法的过程如下:
- x = 1;
- y = 3
- 1和3交换
- 得23541
- 翻转541
- 得23145
/**
* Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
*
* If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
*
* The replacement must be in-place, do not allocate extra memory.
*
* Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
* 1,2,3 → 1,3,2
* 3,2,1 → 1,2,3
* 1,1,5 → 1,5,1
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
void nextPermutation(vector<int>& nums)
{
if (nums.size() < 2) return;
int i = nums.size() - 2;
for (; i >= 0; i--)
{
if (nums[i] < nums[i + 1])
break;
}
if (i < 0)
{
reverse(nums.begin(), nums.end());
return;
}
int k = nums.size() - 1;
for (; k >= 0 && k > i; i--)
{
if (nums[i] < nums[k])
break;
}
swap(nums[i], nums[k]);
reverse(nums.begin() + i + 1, nums.end());
}
int main()
{
vector<int> nums{ 1, 1, 5 };
nextPermutation(nums);
for (size_t i = 0; i < nums.size(); i++)
{
cout << nums[i];
}
cout << endl;
system("pause");
return 0;
}