leetcode 31. Next Permutation

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

这道题如果用暴力法列出所有排列,然后排序,会TLE( 时间复杂度O(n!) )。

我的想法是,序列从右往左开始找,找到第一个 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] > a[i-1]。此时,在a[i1] 右边的序列是倒序排序的,因此右边不会有一个更大的排列了。所以,我们要做的是重新排列 a[i-1] 右边序列 和 它自身。

我们想要获得当前序列的下一个排列,所以需要将
a[i-1]
 和 它右边刚刚比它大一点的那个数交换,假设那个数为 a[j]  


我们交换 a[i-1] and a[j]接下来,对于位于 a[i1] 右边的数字,我们需要让它们形成最小的排列,即让它们升序排列。而因为我们知道在 a[i1] 右边的数字是降序排列的(因为 a[i-1] 和 a[j] 的交换并不会改变这个特性),所以我们只需要翻转 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 : O(n). In worst case, only two scans of the whole array are needed.

  • Space complexity : O(1). No extra space is used. In place replacements are done.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值