其他分享
首页 > 其他分享> > 31. 下一个排列

31. 下一个排列

作者:互联网

题目描述:

  整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。

  整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。

给你一个整数数组 nums ,找出 nums 的下一个排列。必须 原地 修改,只允许使用额外常数空间。

 

解题思路:

示例:

arr = [1,2,3]的全部顺序排序为:
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]

 

  我们应该从后往前遍历相邻两个数字,只要遇到正常升序的两数字,交换它们俩的位置必然能得到一个比原先排列大的排列(如:[1,3,2] -> [3,1,2])。但这并不能保证交换之后得到的是下一个排列,因为后面有比‘3’更小的数字‘2’,将它与‘1’交换得到的排列[2,3,1]比[3,1,2]更接近[1,3,2];但这也不是[1,3,2]的下一排列,因为[2,3,1]数字‘2’后面的序列如果能按升序顺序排列能得到更小的排序[2,1,3],这才是真正的下一排列。因此可以总结出解题步骤如下:

  1. 从后往前遍历,找到升序顺序的相邻两数字 nums[i] nums[i+1] 
  2. 重新从后往前遍历,找到比 nums[i] 大的数字 nums[j]  ,可以保证数字 nums[j] 是子排列 [nums[i+1],nums[i+2],...,nums[n-1]] 中的最小数字
  3. 交换 i 与 j 的位置;
  4. 由于交换之后的子排列 [nums[i+1],nums[i+2],...,nums[n-1]] 必然为非升序,因此只需要将子排列进行反转便可以得到升序的子排序,最后得到的排列就是下一排列。

算法正确性证明:

  以 [...,3,7,5,3,2,1] 这个排列说明一下,在第一步中,我们是以“找升序顺序的两数字”为目的从后往前遍历数组的。因此,在找到数字‘3’之前,遍历过的序列[7,5,3,2,1]必然“满足前一个数字大于或等于后一个数字”(也即非升序)。找到数字‘3’后,我们又在遍历过的序列[7,5,3,2,1]中找比‘3’大的数字‘5’,交换位置后的序列[7,3,3,2,1]必然也满足非升序顺序。因为 nums[i] >=nums[j+1]>=nums[j+2]>=... ,而nums[j-1]>=nums[j],因此交换nums[i]与nums[j]之后,由于nums[j]>nums[i],所以交换过后的子序列:...>nums[j-1]>nums[i]>=nums[j-1]>=...,满足非升序顺序。

 

代码实现:

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var nextPermutation = function(nums) {
    let i = nums.length-2; //对于长度为1的nums,直接跳过循环
    for(;i>=0;i--){
        if(nums[i]<nums[i+1]){
            for(let j=nums.length-1;j>=i+1;j--){
                if(nums[j]>nums[i]){
                    swap(nums,i,j);
                    break;
                }
            }
            reverse(nums,i+1);
            break;
        }
    }
    //如果整个nums为降序序列,那么它的下一排列就是升序序列,直接反转即可
    if(i<0){
        reverse(nums,0);
    }
};
function swap(nums,i,j){
    let temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}
function reverse(nums,start){
    let i = start;
    let j = nums.length-1;
    while(i<j){
        swap(nums,i,j);
        i++;
        j--;
    }   
}

 

标签:...,arr,排列,数字,nums,一个,31,升序
来源: https://www.cnblogs.com/evil-shark/p/16439840.html