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

链接: http://leetcode.com/problems/next-permutation/

题解:

正常倒序应该是654321,假如652431,则2为inversion,并且next permutation应该为653124。

方法是从后向前找inversion,找到第一个inversion,如上例中,然后继续从后向前判断,假如从数组尾部到inversion元素 i 间有数字大于i, 则swap i 和这个数字,由于swap之后依然是倒序,所以我们reverse i 到 nums.length -1。

Time Complexity - O(n), Space Complexity - O(1)。

public class Solution {
    public void nextPermutation(int[] nums) {       // in place, so we consider swap
        if(nums == null || nums.length == 0)
            return;
        
        for(int i = nums.length - 2; i >= 0; i--) {     //find first inversion from end  e.g. - 654231  
            if(nums[i] < nums[i + 1]) {
                for(int j = nums.length - 1; j >= i; j--) {
                    if(nums[j] > nums[i]) {             
                        swap(nums, i, j);                   //swap inversion element and swap i, keep descendent order
                        reverse(nums, i + 1, nums.length - 1);  // i + 1 to nums.length - 1 if possible
                        return;
                    }
                }
            }
        }
        
        reverse(nums, 0, nums.length - 1);              // no inversion
    }
    
    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
    
    private void reverse(int[] nums, int lo, int hi) {
        while(lo < hi)
            swap(nums, lo++, hi--);
    }
}

题外话: 

1-20-2016:

最近刷题的劲头减弱,身体也并不很好,由于压力总是大失眠。给Amazon和Microsoft投递出了简历都是石沉大海,好挫败,常常看地里New Graduate很容易就能拿到onsite或者video interview,只回答几个简单问题就能拿到offer,很羡慕。有时候甚至想辞职去读一个名校CS学位。

负能量比较重。

希望二刷时好好锻炼好思维, 沉住气,耐心按照计划执行。已经付出这么多时间和努力,接下来就是要坚持下去。付出 + 坚持,我相信一定会有回报。自己给自己鼓励吧。

二刷:

主要还是用之前的办法。先从数组后部向前部找第一个正序的数对,比如(2, 3),(2, 4)一类。找到这第一个正序队之后,我们要另外设置一个变量j,也是从数组后部向前部查找,找第一个值nums[j] > nums[i],比如(2, 3, 1)。 找到之后我们要swap(i, j),这样就能保持 i + 1到 nums.length - 1这些数字呈现一个降序的排列,然后我们再reverse(i + 1, nums.length - 1)就可以了。假如数组中没有正序的数对,那么我们根据题意要对整个数组进行逆序。

二刷时看了一下discuss区yavinci大神的代码,真是简洁又漂亮,非常羡慕。

Java:

Time Complexity - O(n), Space Complexity - O(1)

public class Solution {
    public void nextPermutation(int[] nums) {
        if (nums == null || nums.length == 0) {
            return;
        }
        for (int i = nums.length - 2; i >= 0; i--) {
            if (nums[i] < nums[i + 1]) {
                for (int j = nums.length - 1; j > i; j--) {
                    if (nums[j] > nums[i]) {
                        swap(nums, i, j);
                        reverse(nums, i + 1, nums.length - 1);
                        return;
                    }
                }
            }
        }
        reverse(nums, 0, nums.length - 1);
    }
    
    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
    
    private void reverse(int[] nums, int i, int j) {
        while (i < j) {
            swap(nums, i++, j--);
        }
    }
}

三刷:

Java:

public class Solution {
    public void nextPermutation(int[] nums) {
        if (nums == null || nums.length < 2) return;
        int len = nums.length;
        for (int i = len - 2; i >= 0; i--) {
            if (nums[i] < nums[i + 1]) {
                for (int j = len - 1; j > i; j--) {
                    if (nums[j] > nums[i]) {
                        swap(nums, i, j);
                        reverse(nums, i + 1, len - 1);
                        return;
                    }
                }
            }
        } 
        reverse(nums, 0, len - 1);
    }
    
    private void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
    
    private void reverse(int[] nums, int i, int j) {
        while (i < j) swap(nums, i++, j--);
    }
}

Reference:

https://leetcode.com/discuss/8472/share-my-o-n-time-solution

https://leetcode.com/discuss/38247/algorithm-wikipedia-implementation-permutations-permutations

https://leetcode.com/discuss/70881/easiest-java-solution 

https://leetcode.com/discuss/47076/1-4-11-lines-c

原文地址:https://www.cnblogs.com/yrbbest/p/4435212.html