(Leetcode)31. Next Permutation

本文详细解析了31.NextPermutation问题的解决方法,通过递归思路实现数组元素的下一个字典序排列,并介绍了核心步骤:查找可交换的最大元素、交换元素及局部逆序等操作。

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

Problem

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

核心思路

这要求这一个排列与下一个排列有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上

1.递归思路

一个给定数组

int nums[] = {1,3,4,2}
  1. 从后往前,先比较最末尾两个数,nums[head]nums[tail]。其中head=length-2,tail=length-1
  2. 如果nums[head]<nums[tail],那么直接把这两个数互换,next premutation找到,算法complete。e.g.: 1,2,3,4->1,2,4,3
  3. 如果不是,即nums[head]>=nums[tail],那么把head=head-1,向前扩充一个数。
  4. 如果nums[head]>=nums[head+1],继续把head=head-1,再向前扩充一个数,重新回第4步。
  5. 如果不是,即nums[head]>=nums[head+1]
    注意:这个时候nums[head+1] ~nums[tail]一定是降序排列的。
    (a) 找到比在这个范围中比nums[head]大的最小的数,index标记为target。(因为后面的元素一定是是降序排列,所以直接从末尾开始找,第一个就是target)
    (b)把nums[head]和nums[target]互换。
    注意:这个时候nums[head+1]~nums[tail]任然是降序排列的。
    例如:{1,3,4,2}中,nums[head]=3,找到target=2,即’4’的index.互换后数组变成{1,4,3,2},{3,2}任然是降序,但这个不是最终结果。
    (c) 然后对nums[head+1]~nums[tail]进行原地逆序。
    例如:{1,4,3,2}中{3,2}逆序成{2,3},数组变成{1,4,2,3},找到了{1,3,4,2}的next permutation,算法complete。
  6. 如果全部扩充完毕,还是没找到,说明这个数组是个降序数组{4,3,2,1},他的next Permutation是最小的(升序,{1,2,3,4})。直接把这个数组原地逆序就可以了。
重要函数的解释:
  • nextPermutation(int[] nums): 返回nums的下一个全排列
  • ReverseArray(int[] nums, int head, int tail):将nums[]的head~tail的元素原地逆序。

Java

package _31NextPermutation;

public class Solution {
    public void nextPermutation(int[] nums) {
        if(nums.length<=1){
            return;
        }
        else{
            if(recursiveNextPermutation(nums, nums.length-2, nums.length-1)){
                return;
            }
            else{
                ReverseArray(nums,0,nums.length-1);
            }
        }
    }

    boolean recursiveNextPermutation(int[] nums, int head, int tail ){      
        if( head>=tail || head<0 ){
            return false;
        }
        else if( (head+1)==tail ){
            if(nums[head]<nums[tail]){
                int temp = nums[head];
                nums[head] = nums[tail];
                nums[tail] = temp;
                return true;
            }
            else{
                return recursiveNextPermutation(nums,head-1,tail);
            }
        }
        else{
            if(nums[head]<nums[head+1]){
                //find target
                int target = tail;
                while(nums[head]>=nums[target]){
                    target--;
                }
                //swap head and target
                int temp = nums[head];
                nums[head] = nums[target];
                nums[target] = temp;

                ReverseArray(nums, head+1, tail);
                return true;
            }
            else{
                return recursiveNextPermutation(nums,head-1,tail);
            }
        }
    }

    /**
     * reverse the array
     * @param nums
     * @param head
     * @param tail
     */
    void ReverseArray(int[] nums, int head, int tail){
        int i = head;
        int j = tail;
        while(i<j){
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            i++;
            j--;
        }
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int nums[]={1,5,1};
        int k=0;
        while(k<20){
            new Solution().nextPermutation(nums);
            for (int i = 0; i < nums.length; i++) {
                System.out.print(nums[i]+" ");
            }
            System.out.println();
            k++;
        }
    }

}

2.非递归思路

有待更新….

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值