Implement next permutation, which rearranges numbers into the lexicographically(字典序) next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
我的想法是,序列从右往左开始找,找到第一个 a[index]<a[index+1] 的,那么如果要找下一个排列的话, index 前面的数都不要动了,从 index 开始要调整。(如果一直找到 index=-1 都没找到升序的两个数,说明全是降序,根据题意应该返回所有数从小到大排序的序列。)再在 index 右边找到第一个刚刚好比它大一点的,然后与 index 交换。然后把 index 右边的序列从小到大排序,即可。
package leetcode;
public class Next_Permutation_31 {
public void nextPermutation(int[] nums) {
if(nums==null||nums.length==0){
return;
}
int index=nums.length-2;
while(index>=0){
if(nums[index+1]>nums[index]){
break;
}
index--;
}
int low=-1;
if(index==-1){
low=0;
}
else{
int biggerIndex=index+1;
for(int i=biggerIndex+1;i<nums.length;i++){
if(nums[i]>nums[index]&&nums[i]<nums[biggerIndex]){
biggerIndex=i;
}
}
int tmp=nums[index];
nums[index]=nums[biggerIndex];
nums[biggerIndex]=tmp;
low=index+1;
}
sort(nums,low,nums.length-1);
}
public void sort(int[] nums,int left,int right){
if(left<right){
int low=left;
int high=right;
int pivot=nums[low];
while(low<high){
while(low<high&&nums[high]>=pivot){
high--;
}
if(low<high){
nums[low]=nums[high];
low++;
}
while(low<high&&nums[low]<=pivot){
low++;
}
if(low<high){
nums[high]=nums[low];
high--;
}
}
nums[low]=pivot;
sort(nums, left, low-1);
sort(nums, low+1, right);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Next_Permutation_31 n=new Next_Permutation_31();
int[] nums=new int[]{1,1,5};
int[] nums2=new int[]{5,4,7,5,3,2};
n.nextPermutation(nums2);
for(int i=0;i<nums2.length;i++){
System.out.print(nums2[i]+",");
}
}
}
因为我排了序,所以时间复杂度会稍微高一点。下面是solution的解法
https://leetcode.com/problems/next-permutation/solution/ ,时间复杂度是 O(n)。
Algorithm
我们观察到,如果该序列是降序的,那么它的 next larger permutation 应该是它的 reverse。
在其他情况下,我们需要找到从右到左的第一个连续2个数,满足 。此时,在a[i−1] 右边的序列是倒序排序的,因此右边不会有一个更大的排列了。所以,我们要做的是重新排列 右边序列 和 它自身。
我们想要获得当前序列的下一个排列,所以需要将 和 它右边刚刚比它大一点的那个数交换,假设那个数为 。
![](https://i-blog.csdnimg.cn/blog_migrate/b3d4ad613980a83c3ededac2e1aff8e6.png)
我们交换 and 。接下来,对于位于 a[i−1] 右边的数字,我们需要让它们形成最小的排列,即让它们升序排列。而因为我们知道在 a[i−1] 右边的数字是降序排列的(因为 和 的交换并不会改变这个特性),所以我们只需要翻转 右边的数字,即可得到升序排列。
public class Solution { public void nextPermutation(int[] nums) { int i = nums.length - 2; while (i >= 0 && nums[i + 1] <= nums[i]) { i--; } if (i >= 0) { int j = nums.length - 1; while (j >= 0 && nums[j] <= nums[i]) { j--; } swap(nums, i, j); } reverse(nums, i + 1); } private void reverse(int[] nums, int start) { int i = start, j = nums.length - 1; while (i < j) { swap(nums, i, j); i++; j--; } } private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } }
Complexity Analysis
-
Time complexity : . In worst case, only two scans of the whole array are needed.
-
Space complexity : . No extra space is used. In place replacements are done.