31. Next Permutation(下一个排列)
- 1. 题目描述
- 2. 一次遍历(Single Pass Approach)
- 2.1 解题思路
- 2.2 实例代码
1. 题目描述
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
题目链接:中文题目;英文题目
2. 一次遍历(Single Pass Approach)
2.1 解题思路
这道题的难点应该是理解题目在说什么2333。题目重新解释,来源@Susan的评论:
题干的意思是:找出这个数组排序出的所有数中,刚好比当前数大的那个数
————
比如当前 nums = [1,2,3]。这个数是123,找出1,2,3这3个数字排序可能的所有数,排序后,比123大的那个数 也就是132
————
如果当前 nums = [3,2,1]。这就是1,2,3所有排序中最大的那个数,那么就返回1,2,3排序后所有数中最小的那个,也就是1,2,3 -> [1,2,3]
所以我们可以观察一下下面这个例子:
2, 3, 5, 4, 1, 9, 8, 7
从后往前,9, 8, 7是升序,当遇到1时,整个数组变成降序,相当于形成了一个谷底,然后我们在9, 8, 7中选择一个比1大,但是又在三个数中最小的数,即7。交换1和7后,我们把后面的数(9, 8, 1)变成升序(从前往后)就得到了最后答案。
所以解题思路是:
- 从后往前,找到第一个变小的数nums[smallerIdx]和对应序号(smallerIdx);
- 如果找不到,则说明整个数组是降序排序,直接升序排序即可完成;
- 然后从smallerIdx + 1开始,寻找一个比 nums[smallerIdx]大,但是在后面的数中最小的数nextLargerNumber和序号(largerIdx);
- 交换nums[smallerIdx]和nums[largerIdx];
- 升序排序smallerIdx后面的数,后者反转也行;
所以说我们只需要从后往前找到第一个谷底数就可以了,它之前的数已经不影响最后的结果。
注意一下:可以用sort升序排序,也可以使用reverse反转数组,两者结果都是一样的,只是代码中的一个边界判断不大一样。
2.2 实例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | class Solution { // reverse和sort二选一即可 void reverse(vector<int>& nums, int start) { int end = nums.size() - 1; while (start < end) { swap(nums[start], nums[end]); start++; end--; } } public: void nextPermutation(vector<int>& nums) { int len = nums.size(), smallerIdx = -1, largerIdx = -1; // 从后往前找到谷底 for (int i = len - 1; i > 0; i--) { if (nums[i] > nums[i - 1]) { smallerIdx = i - 1; break; } } // 原数组为降序,直接反转即可 if (smallerIdx == -1) { sort(nums.begin(), nums.end()); //reverse(nums, 0); return; } // 找到在剩余数字中最小的,且比谷底数要大的数 int nextLargerNumber = nums[smallerIdx]; for (int j = smallerIdx + 1; j < len; j++) { if (nums[j] > nums[smallerIdx]) { // 使用reverse需要nums[j] <= nextLargerNumber,因为需要保证交换的数为序号最大的那个,否则后面反转会出错;比如[2,3,1,3,3] //如果使用sort只需nums[j] < nextLargerNumber if (nextLargerNumber == nums[smallerIdx] || nums[j] <= nextLargerNumber) { nextLargerNumber = nums[j]; largerIdx = j; } } } swap(nums[smallerIdx], nums[largerIdx]); sort(nums.begin() + smallerIdx + 1, nums.end()); //reverse(nums, smallerIdx + 1); } }; |