Hot100-Day18-T31下一个排列

7 阅读3分钟

Day18[26/3/18]T31下一个排列

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

  • 例如,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

解题思路

首先想到,下一个排列和原排列相比,结构应该是:前 n 个数字都是相同的。

然后对于第 n+1 个数字是,下一个排列上的数字比原排列大一丢丢而已。

此外,第 n+1 位之后的数字应当是升序排列的。

例如说:9874543 的下一个排列应当是 9875344

但是继续观察可以发现,原排列的第 n+1 位之后肯定是降序的,然后下一个排列的 n+1 位之后肯定是升序的,并且第 n+1 位置上要和后面出现过的,仅比第 n+1 位数字大的最小数字交换。

所以算法步骤为:

先从后往前检查是不是全是满足前一位数字大于后一位,如果是,那么恭喜,这就是最大值,下一个排列是最小值,直接 sort。

如果发现第 n 位上的数字大于前一个数字,那么说明前一个数字小了,可以交换成大一点的,那么这个大一点的数字又恰好可以从后往前搜索,搜到的第一个大一点的数字就交换就行。最妙的是,交换完成之后,第 n 位后面的数字依旧是降序的,要改成升序只需要局部 sort 就可以了。

Code

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Solution
{
public:
    void nextPermutation(vector<int> &nums)
    {
        for (int i = nums.size() - 1; i > 0; i--)
        {
            // 找到升序就需要处理
            if (nums[i] > nums[i - 1])
            {
                int j = nums.size() - 1;
                for (; j > i - 1; j--) // 这里可以二分优化
                {
                    if (nums[j] > nums[i - 1])
                    {
                        break;
                    }
                }
                swap(nums[i - 1], nums[j]);
                reverse(nums.begin() + i, nums.end());

                return;
            }
        }

        // 肯定是最大了,要排序成最小
        sort(nums.begin(), nums.end());
    }
};

auto main() -> int
{
    vector<int> nums{1, 2, 3, 4, 5, 4, 3};

    Solution sol;
    cout << "原始: ";
    for (const auto &num : nums)
        cout << num << ",";
    cout << endl
         << "修改: ";
    sol.nextPermutation(nums);
    for (const auto &num : nums)
        cout
            << num << ",";
    cout << endl;
}