本次刷题日记的第 102 篇,力扣题为:31. 下一个排列
一、题目描述:
继续来实实在在的来做 下一个排列的题目
二、这道题考察了什么思想?你的思路是什么?
题目需要我们做得事情比较明确,我们需要注意这几个点
- 题目给出一个整数数组的一个排列,要求我们找到这个nums 的下一个排列
- 什么叫下一个排列呢,指的是 nums 数组的全排列,按照顺序,正好比 nums 排列大的下一个排列
- 题目要求我们只能在原数组 nums 上修改元素,只能使用常数级别的空间消耗
- 且我们需要注意一点,如果当前的 nums 已经是最大的一个排列了,那么咱们就给他变成一个最小的排列
分析
首先,我们来看一下,什么是全排列
简单理解就是按照字典序,来将 nums 数组重新排列的各种排列方式,排列方式一般有 n*F(n-1) 种,其中 F(n-1) 表示 全排列 n-1 个元素的种类
例如,若题目 nums 示例是 [1, 2, 3] ,那么全排列就有 6 种,如下
1 | 2 | 3 |
1 | 3 | 2 |
2 | 1 | 3 |
2 | 3 | 1 |
3 | 1 | 2 |
3 | 2 | 1 |
那这个时候,很明确,如果我们 nums 是 [3, 2, 1] 的话,我们是找不到下一个更大的排列的,因此按照题意,需要我们直接对 nums 进行从下到大排序,咱们也可以直接去翻转 nums 也能得到 [1, 2, 3]
那么我们知道,要找下一个排列,实际上是在所有排列中正好比 nums 排列大的,我们仔细观察上面的全排列,上一行与下一行之间的区别
- 我们会发现,上面一行的从右往左开始第一个小于右边挨着的数 x,总会和 从右往左开始第一个大于 x 的数字 y 进行交换,例如
1 | 2 | 3 |
1 | 3 | 2 |
我们会发现 2 和 3 交换之后,就得到从上一行到下一行的结果了,再如:
1 | 3 | 2 |
2 | 1 | 3 |
我们又发现 ,这个时候我们 从右往左开始第一个小于右边挨着的数 1,与 从右往左开始第一个大于 1 的数字 2 交换了,得到如下结果
2 | 3 | 1 |
然后 3 和 1 还进行了翻转,最终得到
2 | 1 | 3 |
为什么需要翻转呢?
很明显 x 的索引 比 y 的索引靠前,y 的数值又比 x 的数值大
因此 x 和 y 交换之后,数组排列本身已经变大了,x 后面的数据内容,很明显是挨个当前元素大于后面元素的(例如 31),这个时候,我们要尽可能的将这一段数据变小,得到的结果才会是下一个排列
至此,咱们做这个题的时候,实际上就是要知道如何去找到下一个排列的方法:
- 找到符合要求的 2 个数字的索引 i,j,将他们对应的数字交换
- 将 i 后面的数组内容进行翻转即可
一起来愉快的手撸代码吧
三、编码
根据上述逻辑和分析,我们就可以翻译成如下代码
- 从数组右往左遍历,找到第一个小于下一个元素的索引 i , 如果发现 i 小于 0 ,那么只会是当前的排列是最大的了,没有比当前排列还要大的数了,因此需要直接将整个 nums 翻转,变成最小的
- 再从右往左遍历,找到第一个大于 索引i 对一个值的元素索引
- 交换 i 和 j 索引对应的值
- 将 i 后面的元素进行翻转
编码如下:
func nextPermutation(nums []int) { // 从数组右往左遍历,找到第一个小于下一个元素的索引 i i := len(nums) - 2 for i>=0 && nums[i] >= nums[i+1] { i-- } if i < 0 { myReverse(nums[i+1:]) return } // 再从右往左遍历,找到第一个大于 索引i 对一个值的元素索引 j := len(nums) - 1 for j >=0 && nums[i] >= nums[j] { j-- } // 交换 i 和 j 索引对应的值 nums[i], nums[j] = nums[j], nums[i] // 将 i 后面的元素进行翻转 myReverse(nums[i+1:]) return } func myReverse(nums []int){ n := len(nums) for i:=0; i<n/2; i++ { nums[i], nums[n-1-i] = nums[n-1-i], nums[i] } return }
四、总结:
本题的处理方式按照题目中的要求,只引入常数级别的空间消耗,因此空间复杂度是 O(1),
时间复杂度是O(n) ,此处的 n 是 nums 的长度,咱们这种处理方式的实际上顶多会遍历 2 次 nums,和 1次 翻转 nums 的某一段数据
原题地址:31. 下一个排列
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞关注收藏,下次见~