描述
该题来自于力扣第31题
整数数组的一个排列就是将其所有成员以序列或线性顺序排列。
例如,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
分析
仔细分析不难发现,有两个事实:
1. 所有排列中,最小的排列是升序排列,最大的排序是降序排列
2.
如果数组是降序排列,如3 2 1
,则下一个更大的排列不存在,只能回到1 2 3
。
从而若数组a_1 a_2 ... a_{k-1} a_k .... a_n
中从a_k
到a_n
是降序,且a_{k-1} < a_k
,从而a_k ... a_n
已经是最大的排列了,那么按照字典排序,那么下一个排列应该是将k-1
位置上的数换成比a_{k-1}
大的数字,并且应该是a_k .. a_n
中大于a_{k-1}
的所有数中的最小值,不妨设a_j
是该值,那么交换后的排列为a_1 a_2 ... a_j a_k ... a_{k-1} ... a_n
,这时比较两个排列
1 | a_1 a_2 ... a_{k-1} a_k ... a_j ... a_n (1) |
经过前面的分析知道排列(1)
的下一个排列必然是以a_1 a_2 ... a_j
开始的,且后面序列a_k ... a_{k-1} ... a_n
为最小排列即升序排列。又由于a_k ... a_{k-1} ... a_n
是降序,从而将该序列逆序即可得到升序排列了。
比如求3 5 4 2
的下一个排列,这时5 4 2
是降序,而且3 < 5
,由于5 4 2
中比3
大的数为5 4
,其中最小值为4
,所以3
和4
交换,排列变为4 5 3 2
,再将5 3 2
逆序,即得到下一个排列4 2 3 5
。
所以算法主要分三步:
1.
从后往前找,找到第一个a_i > a_{i-1}
,即第一个非降序的排列,记降序排列的起始位置为desc_index
2.
从后往前,找到在desc_index
位置以后的数中第一个大于desc_index-1
位置的数,并交换两个数
3. 逆序从desc_index
开始的所有数
注意到第2步中,在降序排列中找数,可以使用二分查找,当然最简单的方法就是从后往遍历数组。
代码
python3
1 | class Solution: |
c++
1 | class Solution { |