【LeetCode】31. Next Permutations 下一个全排列

来源:互联网 发布:毛笔字生成软件 编辑:程序博客网 时间:2024/05/21 06:39

算法小白,最近刷LeetCode。希望能够结合自己的思考和别人优秀的代码,对题目和解法进行更加清晰详细的解释,供大家参考^_^

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,23,2,1 → 1,2,31,1,5 → 1,5,1

题目让按照字典序生成下一个字典序更大的全排列,如果字典序已经最大,则返回最小的字典序排列。

以之前的全排列问题不同的是(如46题),这一次不能使用递归的方法了。只能使用一种非递归的方法,据说这种方法14世纪的时候就已经提出来了,基本思路是这样的(先来一段摘抄的英文),分为4步:

1. Find the largest index k such that nums[k] < nums[k + 1]. If no such index exists, the permutation is sorted in descending order, just reverse it to ascending order and we are done. For example, the next permutation of [3, 2, 1] is [1, 2, 3].2. Find the largest index l greater than k such that nums[k] < nums[l].3. Swap the value of nums[k] with that of nums[l].4. Reverse the sequence from nums[k + 1] up to and including the final element nums[nums.size() - 1].

简单翻译一下:

1. 找到一个最大的索引k,使得nums[k]<nums[k+1],显然,一旦找到这样的k(k >= 0),说明nums[k+1]>nums[k+2]>nums[n](其中n+1为容器长度,这里只考虑所有元素都不相同的情况),即这些元素是呈递减排列的。如果找不到这样的k,则说明所有元素都呈递减排列,即字典序达到了最大,将其翻转即可2. 找到一个最大的索引l,使用nums[k]<nums[l]3. 交换nums[k]和nums[l]4. 翻转nums[k]后面所有的元素,即翻转nums[k+1]到nums[n]

单纯理解起来可能有些困难,基本思路是把大数往前提,之后再将后面的元素字典序变最小。但按照上述思路写程序还是十分简单的:

class Solution {public:    void nextPermutation(vector<int>& nums) {        int len = nums.size();        int k = -1, l = 0, i = 0;        for (i = len - 2; i >= 0; --i) {            if (nums[i] < nums[i+1]) {                k = i; break;            }        }        if (k == -1) {            reverse(nums.begin(), nums.end()); // 已经是逆序,直接翻转            return ;        }        for (i = len - 1; i >= 0; --i) {            if (nums[i] > nums[k]) {                l = i; break;            }        }        swap(nums[k], nums[l]); // 交换元素位置        reverse(nums.begin() + k + 1, nums.end()); // 翻转元素    }};

这种方法的一个强大之处在于,他已经包含了元素相等的情况,因此不需要再单独考虑了。

有了上面的方法,46题的全排列问题也就迎刃而解了,先将元素排序,然后通过上述方法不断生成下一个全排列,直到所有元素呈逆序排列,就说明我们已经找到了所有的全排列。

原创粉丝点击