LeetCode 31. 下一个排列 | Python

31. 下一个排列


题目


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

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

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

以下是一些例子,输入位于左侧列,其相应输出位于右侧列。

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

解题思路


思路:迭代

首先先理解题意,题目中要求【将给定数字序列重新排列成字典序中下一个更大的排列。如果不存在,则将数字重新排列称最小的排列(即升序排列)】

在这里,可能直接从文字上面来看,不太不能够理解是什么意思,那么结合例子来看,先看

1,2,3 → 1,3,2
1,1,5 → 1,5,1

在这里,你可以理解为,要将数字 123 变为下一个更大的数字,132。115 也同理。

而下面这个例子就是表示不存在更大的排列:

3,2,1 → 1,2,3

321 已经是最大的了,那么就将其排列为最小的排列(升序排列),得到结果 123。

其实从上面的例子中,多多少少也能够看出来,在这里其实是从后面开始找,当找到相邻升序的两个数字,在这里将它们进行交换,这样就能够得到更大的排列。

其实这里还有一部分的内容,在题目中是比较难看出来的,题目中【下一个】这个概念,其实要找到的是变化前后的排列,增加的幅度尽可能小。比如,下面的例子:

1,2,3,4,5 → 1,2,3,5,4
1,2,3,5,4 → 1,2,4,3,5

第一个示例,根据上面观察所得,即是将 4 和 5 进行替换,得到更大的排列,12354。

后面的示例中 12354,得到排列的结果 12435。在这里,交换的是 3 和 4,这里其实交换的数字是尽可能小的大数和前面的小数,所以并不是 3 和 5 进行交换,而交换后的所有数还需要重置升序。所得出的结果是 12435,而不是 12453。

这就是关于题意的简单分析,下面看如何实现算法:

  • 首先需要明确的是从后面往前查找第一个相邻升序的两个元素所在的位置(i,j),满足 A[i] < A[j]。而且,从位置 j 往后的元素是降序的。
  • 在 j 往后的元素中,同样是从后往前找,找到第一个满足 A[i] < A[k] 的元素,将其两者进行交换。
  • 前面说了, 从 j 往后一定是降序的,那么交换以后肯定也是降序的(因为找到 A[k] 是第一个比 A[i] 大的数字,由于是从后往前找,k所在位置左边的数字势必比当前 i 所在位置的数字大,而右边的数字也就比其小),这个时候,要将这部分降序,逆转为升序,这样才能保证排列前后尽可能小的增幅。
  • 考虑特殊的情况,也就是整个排列是降序,即是最大的的排列时,执行上面所说逆转为升序即可。

具体的代码实现如下。

代码实现


class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        if len(nums) < 2:
            return

        n = len(nums)

        # 从数组右往前进行遍历,查找相邻升序元素
        i = n - 2
        j = n - 1
        while i > 0 and nums[i] >= nums[j]:
            i -= 1
            j -= 1
        # 这里有一种情况,就是循环结束后,i 为 0 且索引 0 位置的数是最大的情况
        # 那这里就表示排列就是最大的排列,将其逆转升序
        if i == 0 and nums[i]==max(nums):
            nums.reverse()
        else:
            # 当找到相邻的升序元素时
            # 再次从后往前找到一个比 nums[i] 大但相比其他元素尽可能小的数
            k = n - 1
            while nums[i] >= nums[k]:
                k -= 1
            # 交换两个元素
            nums[i], nums[k] = nums[k], nums[i]

            # 现在 j 到后面的元素是降序的,这里要将其升序
            length = n - j + 1
            for x in range(length // 2):
                nums[j+x], nums[n-1-x] = nums[n-1-x], nums[j+x]

实现结果


实现结果

以上就是关于《31. 下一个排列》问题的分析及具体实现算法的主要内容。


欢迎关注微信公众号《书所集录》

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351