0
点赞
收藏
分享

微信扫一扫

LeetCode 热题 HOT 100 第十四天 31. 下一个排列 用python3求解

香小蕉 2022-04-14 阅读 52

题目地址

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

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

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

示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]

示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]

示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]

提示:
1 <= nums.length <= 100
0 <= nums[i] <= 100
在这里插入图片描述
解题思路
解释:
字典序: 也就是序列全部的排列组合
下一个更大的: 比如 [1,2,3](123) 下一个更大的就是 [1,3,2](132)

以下解题思路参考:地址
解题思路:

  1. 首先需要从后往前找, 因为 位数是 (… 万千百十个)这样子的, 要从个位往上找(从右向左)
  2. 以 123(最小的数)为例。 逆着找 3(个位) > 2 十位 ,则直接进行交换 132 就是最小的
  3. 132, 逆着找(右向左), 1(百位) < 3(十位) 则 进行交换 这时候需要用 十位,个位当中最小的替换,就成了231
  4. 231 显然不是最接近 132的, 需要将 十位,个位逆序。因为 第三步中间判断到 1(百位了),说明 个位 < 十位(2 < 3), 百位 < 十位(1 < 3), 所以将剩下的 十位,各位逆序,才能是最小的。 变成 213
  5. 此时 213. 逆着找 1 小于 3, 那就直接 变为 2 31
  6. 此时 231. 逆着找 2 小于 3,需要寻找 比2 大一点的数(最接近2的) 变为 321, 然后 反转312
  7. 312 变为 321
  8. 321 是最大的了, 低位比高位大的。 所以全部反转 123

再举一个例子: 452631

  1. 首先找到低位比高位大的 2 6
  2. 从 2 后面调出来 最接近2的,需要大于2. 也就是3, 交换变为 453621
  3. 低位的数字逆序 变为 453126(为什么能直接逆序后面的数字,因为既然选择到2 6,和3 ,2 一定 大于等于3之后的数,如果不大于,那就选择3之后的数了)

总结一下,数组num长度n,下标i范围为0~n-1,从数组的n-1位置出发,往下标为0的方向查找(逆序遍历),找到num[i-1]小于num[i]的值,那么就重点关注这个num[i-1]的值。
在这基础上,再来一次逆序遍历查找比num[i-1]大的值,且是这些值里的最小值(也就是说,找到一个值,该值比num[i-1]大,但也是所有比num[i-1]大的值里面的最小值),那么就把该值与num[i-1]两值调换。
最后,反转数组里下标为i到n-1的值。即将num[i],num[i+1],…,num[n-1],num[n],反转为num[n],num[n-1],…,num[i+1],num[i]。

代码实现:

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

        def reverse(low, high):
            """ 用来进行反转 """
            while low < high:
                nums[low], nums[high] = nums[high], nums[low]
                low, high = low + 1, high - 1

        # 写代码实现
        n = len(nums)
        for i in range(n-1, 0, -1):      
            # 如果高位小于低位数字
            if nums[i-1] < nums[i]:
                # 完成 高位 与最接近且大于它的低位进行交换, 最接近的低位,一定是逆序遍历大于它的第一个数
                for j in range(n-1, 0, -1):
                    if nums[j] > nums[i-1]:
                        nums[i-1], nums[j] = nums[j], nums[i-1]
                        break
                # 再将高位往后的低位进行逆序
                reverse(i, n-1)
                break
        else:
            # 正常循环结束,则说明是最大的直接反转
            reverse(0, n-1)//像示例2那样的特殊情形

注:for i in range(n-1, 0, -1)表示从n-1到0(不包括0),步长为-1
平时没有写第三个值,是因为默认步长为1

如:range(1,4,2):从1到4,步长为2,即1,3

举报

相关推荐

0 条评论