跳转至

31. 下一个排列

最后更新:2024-05-12-22

链接:https://leetcode.cn/problems/next-permutation/description/

题目描述

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

  • 例如,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 的下一个排列。

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

题目示例

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

输出: [1,3,2]

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

输出: [1,2,3]

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

输出: [1,5,1]

提示:

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

分割数组,然后排序,交换

C
int compare(void *a, void *b)
{
    return *(int*)a - *(int*)b;
}

void swap(int *a, int *b) {
    int t = *a;
    *a = *b, *b = t;
}

int findLastPeakPos(int* nums, int numsSize)
{
    int cur = numsSize - 2;
    while (cur >= 0) {
        if (nums[cur + 1] > nums[cur]) {
            break;
        }
        cur--;
    }
    cur++;

    return cur;
}

int findSwapPos(int* nums, int numsSize, int pos)
{
    for (int i = pos; i < numsSize; i++) {
        if (nums[i] > nums[pos]) {
            return i;
        }
    }

    return -1;
}

void nextPermutation(int* nums, int numsSize)
{
    if ((nums == NULL) || (numsSize < 2)) {
        return;
    }

    int last_peak = findLastPeakPos(nums, numsSize);
    qsort(nums + last_peak, (numsSize - last_peak), sizeof(int), compare);
    if (last_peak < 1) {
        return;
    }

    int swap_pos = findSwapPos(nums, numsSize, (last_peak - 1));
    if (swap_pos < 0) {
        return;
    }

    swap(&nums[last_peak - 1], &nums[swap_pos]);
}

我们可以把当前的序列分割成两个子序列a和b,以从后往前的第一个峰值为中心点。

那么中心点之后的子序列,其下一个序列必然是对b进行升序重排列的序列。

因为下一个序列要比当前序列更大,那么我们只能找到b中比a大的第一个值,然后两个数字交换即可

  1. 从后往前找到第一个降序的值a = nums[pos]
  2. 从后往前找到比a大的那个值b
  3. 交换a、b两个值
  4. 对pos 之后的数组进行升序排序

特殊:如果本身就是降序的,那么下一个序列就是全数组升序。

C
int compare(void *a, void *b)
{
    return *(int*)a - *(int*)b;
}

void swap(int *a, int *b) {
    int t = *a;
    *a = *b, *b = t;
}

void nextPermutation(int* nums, int numsSize)
{
    if ((nums == NULL) || (numsSize < 2)) {
        return;
    }

    // 第一步,从后往前找第一个下降的点
    int i = numsSize - 2;
    while (i >= 0) {
        if (nums[i + 1] > nums[i]) {
            break;
        }
        i--;
    }

    if (i < 0) {
        // 整改序列是降序的,直接重排
        qsort(nums, numsSize, sizeof(int), compare);
        return;
    }

    int j = numsSize - 1;
    while (j >= 0) {
        if (nums[j] > nums[i]) {
            break;
        }
        j--;
    }
    
    swap(&nums[i], &nums[j]);

    // 对i之后的进行排序
    qsort(&nums[i + 1], (numsSize - i - 1), sizeof(int), compare);
}