Leetcode 031 下一个排列 思路详解+反思易错 python实现

本人一直在努力地积累Leetcode上用Python实现的题,并且会尽力讲清每道题的原理,绝不像其他某些博客简略地带过。
如果觉得讲的清楚,欢迎关注。




实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

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

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,31,3,2
3,2,11,2,3
1,1,51,5,1




思路:我采用的是升序倒置法,具体:

下一个排列,其实本质上找的是下一个比当前数字大的数。当然,最后一种排列,也就是3,2,1这种找的是第一个。

123,下一个紧挨着123且稍稍大于123的数是132。也就是说我们要做一些调整,让我们当前数字增加,但同时增加幅度要最小。

本着这样的思路,当然是从后往前遍历,因为尾部的权重比较低(个位,十位。。。),改变起来增加的小。如果我们从后往前遍历,遍历的值都一直在增加,也就是如果一直升序的话,我们不可能说交换这个升序空间内的两个值来达到增加的目的。

比如465321,从后往前遍历到3之前,123是升序空间,我们不可能操作2个数字交换达到增值。

于是我们得找到第一个断点,在这个例子中就是4。断点即第一次前面的数比后一位数大了。找到这个断点,我们交换的其中一个目标就确定了,于是我们要找另一个交换目标?找谁合适呢?找3,那么整体减小;找6,那么整体确实增加,但好像不是最优;答案是找5,5也是从尾部开始数第一个比4(交换目标)大的数。(至于为什么从尾部遍历,其实是我们想降低交换带来的权重变化)好,于是我们的整体变成了564321。这个564321还不是最终答案,因为我们发现我们可以对5以后的所有数字进行排序,变成512346。这时才是我们要找的结果!

至于654321这种,直接判断它的升序空间末位置(6)的下一位为空,则返回一个123456(完全逆序)。


class Solution:
    def nextPermutation(self, nums):
        """
        :type nums: List[int]
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        i = len(nums) - 1
        if len(list(set(nums))) != 1:
            
            #先从尾部升序结束的点
            while i - 1 >= 0:
                if nums[i] <= nums[i - 1]:
                    i = i - 1
                else:
                    break
            #如果前面还有至少一个位置
            if i - 1 >= 0:
                j = i - 1

                t = len(nums) - 1
                #从后往前找第一个大于j位置上的数
                while nums[t] <= nums[j]:
                    t -= 1
                nums[t], nums[j] = nums[j], nums[t]
                a = sorted(nums[i:])
                a_index = 0
                #因为我不知道python分段排序的方法,于是就手动排序
                #以下是对nums的排序
                for index in range(i, len(nums)):
                    nums[index] = a[a_index]
                    a_index += 1
            #没有位置则sort
            else:
                nums.sort()

反思总结:排列,实际上是一组有大小顺序的排列数。

猜你喜欢

转载自blog.csdn.net/weixin_41958153/article/details/80830211