LeetCode(十)------Next Permutation

本文详细介绍了一个高效的算法,用于找出给定数字序列的下一个字典序排列。通过实例解析,阐述了算法的具体步骤,包括查找断点、寻找替换值、交换元素和反转子序列等关键操作。

摘要生成于 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


  • 思路:
    排列(Arrangement),简单讲是从N个不同元素中取出M个,按照一定顺序排成一列,通常用A(M,N)表示。当M=N时,称为全排列(Permutation)。从数学角度讲,全排列的个数A(N,N)=(N)(N-1)…*2*1=N!,但从编程角度,如何获取所有排列?那么就必须按照某种顺序逐个获得下一个排列,通常按照升序顺序(字典序)获得下一个排列。

    例如对于一个集合A={1,2,3,},首先获取全排列a1: 1,2,3,;然后获取下一个排列a2: 1,3,2,;按此顺序,A的全排列如下:

    1,2,3 
    1,3,2
    2,1,3
    2,3,1 
    3,1,2 
    3,2,1



  • 下一个全排列(Next Permutation)
    对于给定的任意一种全排列,如果能求出下一个全排列的情况,那么求得所有全排列情况就容易了
    题目中给的例子可以看出来,如果给定数组是降序,则说明是全排列的最后一种情况,则下一个排列就是最初始情况。再来看下面一个例子,有如下的一个数组

    1  2  7  4  3  1

    下一个排列为:

    1  3  1  2  4  7

    那么是如何得到的呢,通过观察原数组可以发现,如果从末尾往前看,数字逐渐变大,到了2时才减小的,然后我们再从后往前找第一个比2大的数字,是3,那么我们交换2和3,再把此时3后面的所有数字转置一下即可,步骤如下:

    1  2  7  4  3  1

    1  2  7  4  3  1

    1  3  7  4  2  1

    1  3  1  2  4  7

    算法具体过程如下图所示:
    这里写图片描述


  • 代码示例:
// Time Complexity: O(n), Space Complexity: O(1)
public class Solution {
    public void nextPermutation(int[] nums) {
        nextPermutation(nums, 0, nums.length);
    } 
    private static boolean nextPermutation(int[] nums, int begin, int end) {
        // 1. From right to left, find the first digit(partitionNumber)
        // which violates the increase trend
        int p = end - 2;
        while (p > -1 && nums[p] >= nums[p + 1]) --p;
        // If not found, which means current sequence is already the largest
        // permutation, then rearrange to the first permutation and return false
        if(p == -1) {
            reverse(nums, begin, end);
            return false;
        } 
        // 2. From right to left, find the first digit which is greater
        // than the partition number, call it changeNumber
        int c = end - 1;
        while (c > 0 && nums[c] <= nums[p]) --c;
        // 3. Swap the partitionNumber and changeNumber
        swap(nums, p, c);
        // 4. Reverse all the digits on the right of partitionNumber
        reverse(nums, p+1, end);
        return true;
    } 
    private static void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    } 
    private static void reverse(int[] nums, int begin, int end) {
        end--;
        while (begin < end) {
            swap(nums, begin++, end--);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值