每日一题:下一个排列

60 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

题目链接

整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。

  • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3][1,3,2][3,1,2][2,3,1] 。

整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

  • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
  • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
  • 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

给你一个整数数组 nums ,找出 nums 的下一个排列。

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

 

示例 1:

输入: nums = [1,2,3]
输出: [1,3,2]

示例 2:

输入: nums = [3,2,1]
输出: [1,2,3]

示例 3:

输入: nums = [1,1,5]
输出: [1,5,1]

 

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

解题思路

以数组arr = [1,2,3]举例,arr共有这几种排列:(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)

通过上面的排序我们可以得到这样的关系:(1,2,3) < (1,3,2) < (2,1,3) < (2,3,1) < (3,1,2) < (3,2,1)

因为我们需要得到上面的排列数序,所以

  1. 因为题目中要求,下一个排列数要比当前排列数大,因此就可以将排列数后面的大数和小数进行交换,这样就得到了更大的数,拿(1,2,3)举例来说,我们交换数组中的2,3,得到的新排列数(1,3,2)就大于(1,2,3)了
  2. 题目中还要求下一个排列要和当前排列紧邻,我们每次增加排列的幅度要很小,因此
    1. 我们可以从低位往高位寻找,需要从后向前找
    2. 尽可能小的「大数」 与前面的「小数」进行交换,比如(1,3,2),这里更大的小数就是2,更小的大数就是1,交换得到(2,3,1)
    3. 将大数换到前面后,我们还需要将大数后面的进行升序排序,因为升序后的排列最小,比如(1,3,2),进行第二步交换后,得到(2,3,1),将2后面的数组进行升序排列,得(2,1,3),所以(1,3,2)的下一个排列就是(2,1,3)

算法描述

  1. 从后向前查找第一个相邻升序的元素对 (i,j),满足 A[i] < A[j]。此时 [j,end) 必然是降序
  2. 在 [j,end) 从后向前查找第一个满足 A[i] < A[k]kA[i]、A[k] 分别就是上文所说的「小数」、「大数」
  3. A[i]A[k] 交换
  4. 可以断定这时 [j,end) 必然是降序,逆置 [j,end),使其升序
  5. 如果在步骤 1 找不到符合的相邻元素对,说明当前 [begin,end) 为一个降序顺序,则直接跳到步骤 4

具体代码:JAVA

class Solution {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        int j = nums.length - 1;

        while (i >= 0) {
            if (nums[i] < nums[j]) {
                break;
            }
            i--;
            j--;
        }

        if (i < 0) {
            reserver(nums,0,nums.length - 1);
            return;
        }

        int end;
        for (end = nums.length - 1; end >= j; end--) {
            if (nums[end] > nums[i]) {
                break;
            }
        }

        swap(nums,i,end);

        reserver(nums,j,nums.length - 1);
    }

    //升序排序
    public void reserver(int[] arr,int i,int j) {
        while(i < j) {
            swap(arr,i,j);
            i++;
            j--;
        }
    }

    //交换元素
    public void swap(int[] arr,int i,int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}