今天力扣的每日一题是第31题,非常靠前的一道题。本来打算把以前的提交复制过去拿下10积分的,没想到以前竟然没有做过这道题。这就非常有趣了,为什么这么靠前的题,难度又是中等,以前就跳过了呢?
看了一遍题目。是排列的问题,上一次想做这道题时,因为没有注意到 "lexicographically next greater permutation" 这句话,我不明白什么是下一个排列,不知道排列的顺序,所以跳过了。
仔细看了一遍题目,求的是下一个比当前序列表示的数更大的数,如果不存在,就返回最小的那个序列,与556 Next Greater Element III 类似,那道题的参数是一个数,如果没有更大的数就返回-1。
理解题意后,觉得这道题不像是考动态规划,贪心等算法,直接用暴力方法试试。这样的任务交给我,我会怎么做呢?
从右向左看:
-
如果是递增的,即每个数都比他左边的数小(如有),那么用这些数无法组成更大的数了,反转这个数组,返回。
-
如果序列中存在某个数,比他左边的数大,那么就能通过重新排列这些数字,获得下一个序列。怎么调整呢?要把这个左边的不懂规矩的“小”数,换成其右边比他大的数中的最小的那个(就是只比他大的那个),其余数字,从小到大排列。
举个例子,输入 [1, 2, 3, 7, 6, 5],输出 [1, 2, 5, 3, 6, 7]
- 进一步发现,在遇到这个不懂规矩的“小”数前,所有的数都是递增的,所以 “其余数字,从小到大排列” ,其实就是反转的过程。
最终代码
static int x = [] () {ios::sync_with_stdio(false); cin.tie(0); return 0;} ();
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) --i;
if (i != -1)
for (int j = nums.size() - 1; j > i; --j)
if (nums[j] > nums[i]) {
swap(nums[i], nums[j]);
break;
}
reverse(nums.begin() + i + 1, nums.end());
}
};