文章目录
- 题目描述
- 思路 && 代码
- 二刷
打卡第八天~
题目描述
- 需要花点时间思考的一道题,这篇题解写得很好。
思路 && 代码
- 主要分为这三个步骤:
- 从后往前找到满足 nums[first] < nums[first + 1] 的索引 first
- 从后往前找到满足 nums[second] > nums[first] 的索引 second
- 交换 nums[first]、nums[second],翻转 nums[ first + 1 : ]
- 对于步骤1,找不到 first 时翻转整个数组,也就是当前排列为最大排列的情况。
- 对于步骤2,nums[second] 一定是最接近 nums[first] 的值(可以证明)
- 步骤3进行交换后,有 nums[first + 1 : ] 满足 nums[i] > nums[i + 1],即当前排列为nums[first + 1 : ] 的最大排列;那么对nums[first : ]进行一个翻转,即可得到 nums[first : ]的最小排列,也就是最接近初始排列的下一个排列。
- 借用leetcode 题解区 powcai 大佬的例子:
- 对于 nums = [1, 2, 7, 4, 3, 1]
- 找到 nums[first] = nums[1] = 2
- 找到 nums[second] = nums[4] = 3
- 交换 nums = [1, 3, 7, 4, 2, 1](可以看到 7 4 2 1 是刚好降序排列的)
- 翻转 nums = [1, 3, (1, 2, 4, 7)] (刚好变成 1, 3 开头的最小排列,是1, 2 排列的最大排列的下一个排列)
- 复杂度 O(n) 、O(1),很有意思的一道题,可以多看看~
class Solution {public void nextPermutation(int[] nums) {// Case 1: 空数组 or 无元素if(nums == null || nums.length == 0) {return; }// 1. 先找最大索引 k,满足 nums[k] < nums[k + 1];不存在则翻转整个数组int firstIndex = -1;int len = nums.length;// 从后往前找for(int i = len - 2; i >= 0; i--) {if(nums[i] < nums[i + 1]) {firstIndex = i;break;}}// Case 2: 找不到的情况,直接翻转数组(即本就是最大排列)if(firstIndex == -1) {reverse(nums, 0, len - 1);return;}// 2. 然后找到第二个最大索引:满足 nums[sec] > nums[first]int secondIndex = -1;// 同样是从后往前找,找到的第一个肯定是最接近 nums[first]的值for(int i = len - 1; i >= 0; i--) {if(nums[i] > nums[firstIndex]) {secondIndex = i;break;}}// 3. 先交换 first 和 second(交换后,当前序列为nums[first : second]的最大序列)swap(nums, firstIndex, secondIndex);// 4. 然后对 nums[first + 1 :] 进行翻转(翻转后,当前序列为nums[first : second]的最小序列)reverse(nums, firstIndex + 1, len - 1);}// 翻转函数public void reverse(int[] nums, int i, int j) {while(i < j) {swap(nums, i++, j--);}}// 交换函数public void swap(int[] nums, int i, int j) {int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
}
二刷
- keywords:两个下标、交换、翻转
- firstIndex:第一个与后面的元素交换,能让排列变大的元素
- 交换:让排列变大
- 翻转:在大于初始排列的情况下,让排列变得最小。
class Solution {public void nextPermutation(int[] nums) {int firstIndex = nums.length;for(int i = nums.length - 2; i >= 0; i--) {if(nums[i] < nums[i + 1]) {firstIndex = i;break;}}if(firstIndex == nums.length) {reverse(nums, 0, nums.length - 1);return;}int secondIndex = nums.length;for(int i = nums.length - 1; i >= 0; i--) {if(nums[i] > nums[firstIndex]) {secondIndex = i;swap(nums, firstIndex, secondIndex);break;}}reverse(nums, firstIndex + 1, nums.length - 1);}void reverse(int[] nums, int left, int right) {while(left < right) {swap(nums, left++, right--);}}void swap(int[] nums, int left, int right) {int temp = nums[left];nums[left] = nums[right];nums[right] = temp;}
}