代码题(45)— 下一个排列、第k个排列 Permutations 全排列

1、31. 下一个排列

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须原地修改,只允许使用额外常数空间。

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

这道题让我们求下一个排列顺序,有题目中给的例子可以看出来,如果给定数组是降序,则说明是全排列的最后一种情况,则下一个排列就是最初始情况,可以参见之前的博客 Permutations 全排列。我们再来看下面一个例子,有如下的一个数组

1  2  7  4  3  1

下一个排列为:

1  3  1  2  4  7

那么是如何得到的呢,我们通过观察原数组可以发现,如果从末尾往前看,数字逐渐变大,到了2时才减小的,然后我们再从后往前找第一个比2大的数字,是3,那么我们交换2和3,再把此时3后面的所有数字转置一下即可,步骤如下:

1  2  7  4  3  1

1  2  7  4  3  1

1  3  7  4  2  1

1  3  1  2  4  7

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        if(nums.empty())
            return ;
        int n=nums.size();
        int i=n-2,j=n-1;
        while(i>=0 && nums[i]>=nums[i+1])// 从后向前,找到第一个违反升序的数的位置
            i--;
        if(i>=0)
        {
            while(j>=0 && nums[j]<=nums[i]) // 从后向前,找到第一个大于该数的值的位置
                j--;
            swap(nums[i],nums[j]); // 交换二者的值
        }
        reverse(nums.begin() + i + 1, nums.end()); //将后面的数重新排序
    }
};

2、60. 第k个排列

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。

按大小顺序列出所有排列情况,并一一标记,当 = 3 时, 所有排列如下:

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

给定 n 和 k,返回第 k 个排列。

说明:

  • 给定 n 的范围是 [1, 9]。
  • 给定 的范围是[1,  n!]。

示例 1:

输入: n = 3, k = 3
输出: "213"

示例 2:

输入: n = 4, k = 9
输出: "2314"

  我们可以发现,每一位上1,2,3,4分别都出现了6次,当第一位上的数字确定了,后面三位上每个数字都出现了2次,当第二位也确定了,后面的数字都只出现了1次,当第三位确定了,那么第四位上的数字也只能出现一次,那么下面我们来看k = 17这种情况的每位数字如何确定,由于k = 17是转化为数组下标为16。

class Solution {
public:
    string getPermutation(int n, int k) {
        string res;
        string nums = "123456789";
        vector<int> f(n, 1);
        for (int i = 1; i < n; ++i)
            f[i] = f[i - 1] * i;
        k--;//因为下标从0开始。
        
        for (int i = n - 1; i >= 0; --i)
        {
            int temp = k/f[i];
            k = k%f[i];
            res.push_back(nums[temp]);
            nums.erase(temp, 1);
        }
        return res;
    }
};

猜你喜欢

转载自www.cnblogs.com/eilearn/p/9482141.html