首页 > 编程语言 >算法随笔_6: 下一个排列

算法随笔_6: 下一个排列

时间:2025-01-15 16:58:46浏览次数:3  
标签:排列 num nums len 算法 p1 升序 随笔

上一篇: 算法随笔_5:接雨水-CSDN博客

题目描述如下:

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

  • 例如,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 的下一个排列。

必须 原地 修改,只允许使用额外常数空间。

==============================

解题思路:

根据题目要求已知一个整数的排列,需要求出按字典序的下一个排列。也就是说,找到下一个比当前这个数更大的数,且这两个数要紧挨着。例如下面这些按字典序的排列:

12345

12354

12435

12453

12534

...

54321

首先,我们需要保证数值是增大的。

其次,要保证数值是逐渐增大的。

如何保证第一点呢?很明显,降序的排列肯定比升序的排列数值大。

如何保证第二点呢?我们一起来看一下下面的分析:

上面第一行"12345",45是升序,那好,我们交换一下它俩让其变为降序54就可以了。

第二行"12354",从右往左看,54本身就是降序,说明最后两位的字典序排列已经是最大数了,我们需要继续往左找,发现是35升序,从这儿开始,我们需要把后三位重新排列,并且要保证数值是逐渐增大。重新排列的原则就是从后面两位中找一个比3大的最小数,然后剩下的两位需要按升序排列。这样就变成了12435。这个例子可能不明显,我们换一个例子,比如: 12398,它的下一个就是12839。这里大家可能有个疑问,刚才我们提到降序能保证数值增大,这里为什么又按升序排列?因为我们既要保证数值增大,而且要保证数值是逐渐增大的。既然,需要变动的后三位的高位已经变大,那这个数值一定比以前的数值大。但要保证逐渐增大,所以剩下的低位按照升序排列。

到此时,算法的雏形已经基本完成,给定一个排列,我们就可以按照这个原则去重新排列,即可得到下一个大数。

剩下的问题我们就需要考虑算法的效率问题了。算法涉及三个阶段:

第一阶段,从后往前找到需要变动的最少位数。这个问题一次迭代就能搞定。从后往前的数字需要不断变大,爬升,当发现数字变小,下降时,即找到了需要变动的位数。我们可以用一个指针p来做这一步。

第二阶段,需要从p指针所指数字num后面的位数中找一个比num大的最小数。然后两者交换。

第三阶段,我们需要把剩余的位数做升序排列。因为此时num后面的位数仍然保持降序,所以两两首尾交换,即可。

整个算法,我们只使用了一个tmpNum的变量,来临时存储交换时的值,因此符合题目要求的“原地”修改数组,只使用额外常数空间。算法时间复杂度为O(N),空间复杂度为O(1)。

以下是Python版的代码:

class Solution:
    def swap(self, nums, i, j):
        tmpNum=nums[i]
        nums[i]=nums[j]
        nums[j]=tmpNum

    def nextPermutation(self, nums):
        num_len=len(nums)
        p1=0
        p2=0
        #第一阶段,从后往前找到需要变动的最少位数,p1指向降序的最高位,因此需要增大的是p1-1下标处
        for i in range(1, num_len):
            num2=nums[num_len-i]
            num1=nums[num_len-i-1]
            if num1<num2:
                p1=num_len-i
                break
        if p1>0:
            #如果p1>0, 第二阶段,需要从nums[p1-1]后面的位数中找一个比nums[p1-1]大的最小数
            #如果p1==0 表示整个数组就是降序排列,直接跳过此步骤
            for i in range(p1, num_len):
                if nums[p1-1]>=nums[i]:
                    p2=i
                    break
            self.swap(nums, p1-1, p2-1) #找到后交换位置
        #第三阶段,我们把剩余的位数,做升序排列。因为本身就是降序列,所以两两首尾交换,即可。
        cnt=int((num_len-p1)/2)
        for i in range(cnt):
            self.swap(nums, p1+i, num_len-i-1)
# 示例用法
solution = Solution()
#nums=[1,2,3,9,8,6,1]
#nums=[1,1,1]
#nums=[5,4,3,2,1]
nums=[1,5,1]
solution.nextPermutation(nums)
print(nums)

标签:排列,num,nums,len,算法,p1,升序,随笔
From: https://blog.csdn.net/m0_70494097/article/details/145140801

相关文章

  • 【前端】自学基础算法 -- 25.动态规划-01背包问题
    动态规划-01背包问题简介动态规划(DynamicProgramming,简称DP)是一种解决复杂问题的方法,它将问题分解为更小、更简单的子问题,并存储这些子问题的解,以避免重复计算。动态规划通常用于优化问题,如求最大值、最小值或计数问题。动态规划的基本思想是将大问题分解为小问题,并从......
  • 2025-1-15-十大经典排序算法 C++与python
    文章目录十大经典排序算法比较排序1.冒泡排序2.选择排序3.插入排序4.希尔排序5.归并排序6.快速排序7.堆排序非比较排序8.计数排序9.桶排序10.基数排序十大经典排序算法十大经典排序算法可以分为比较排序和非比较排序:前者包括冒泡排序、选择排序、插......
  • 模式识别课程设计报告-Iris鸢尾花样本集多种分类算法实现
     课程实验报告,从前人的总结分享中学习借鉴了很多,上传记录,或许能帮到有需要的人。任务一:(1)从sklean中导入iris数据集(2)从CSV文件中导入iris数据集任务二:(1)利用sklearn中的model_selection.train_split()函数将样本集划分为训练集和测试集(2)定义一个函数plot_points(),该函数的功能......
  • 字符串匹配(BP&KMP算法)
    BP&KMP算法字符串匹配前言BP算法(基础)引文KMP算法(进阶)伪代码描述next数组递归求解思路算法思路详解KMP算法实现及测试(先做在看!)字符串匹配前言本文是基于懒猫老师的课程----BP&KMP所写,在观看本文之前最好配合视频或者PPT食用更佳,地址我附在下面:https://www.bilibi......
  • ISP基本框架及算法介绍
    ISP(ImageSignalProcessor),即图像处理,主要作用是对前端图像传感器输出的信号做后期处理,主要功能有线性纠正、噪声去除、坏点去除、内插、白平衡、自动曝光控制等,依赖于ISP才能在不同的光学条件下都能较好的还原现场细节,ISP技术在很大程度上决定了摄像机的成像质量。它可以分......
  • 科普文:算法和数据结构系列【压缩和通信利器:哈夫曼树(Huffman Tree)java示例代码解读】
    概叙科普文:算法和数据结构系列【算法和数据结构概叙】-CSDN博客科普文:算法和数据结构系列【非线性数据结构:树Tree和堆Heap的原理、应用、以及java实现】-CSDN博客科普文:算法和数据结构系列【树:4叉树、N叉树】-CSDN博客科普文:算法和数据结构系列【二叉树总结-上篇:满二叉树、......
  • 算法-移除元素
     力扣题目:27.移除元素-力扣(LeetCode)给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作......
  • 【轻松掌握数据结构与算法】字符串算法(String Algorithms)
    字符串算法概述字符串匹配算法是计算机科学中的一个重要领域,主要用于在文本中查找特定模式(子字符串)的出现位置。这些算法在文本编辑器、搜索引擎、生物信息学等领域有广泛的应用。暴力法(BruteForceMethod)暴力法是最直接的字符串匹配算法,它通过逐个字符比较来查找模式在文......
  • 算法面试准备 - 手撕系列第二期 - 交叉熵损失(Cross Entropy Loss)
    算法面试准备-手撕系列第二期-交叉熵损失(CrossEntropyLoss)目录算法面试准备-手撕系列第二期-交叉熵损失(CrossEntropyLoss)交叉熵原理图交叉熵损失实现代码-不同y_pre版本参考交叉熵原理图Softmax原理图交叉熵损失实现代码-不同y_pre版本......
  • 期望最大化算法:机器学习中的隐变量与参数估计的艺术
    引言在机器学习和统计学领域,许多实际问题涉及到含有隐变量的概率模型。例如,在图像识别中,图像的语义信息往往是隐变量,而我们能观测到的只是图像的像素值;在语音识别中,语音对应的文本内容是隐变量,观测数据则是语音信号。期望最大化(Expectation-Maximization,简称EM)算法作为一......