ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

31. 下一个排列

2022-07-03 15:05:24  阅读:140  来源: 互联网

标签:... arr 排列 数字 nums 一个 31 升序


题目描述:

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

  • 例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。

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

  • 例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
  • 类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
  • 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。

给你一个整数数组 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有