31. Next Permutation

本文详细解析了LeetCode上的'下一个排列'问题,包括解题思路、时间复杂度、空间复杂度分析,以及提供了Java代码实现,帮助读者理解和解决相关问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值