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 的下一个排列。
    必须 原地 修改,只允许使用额外常数空间。

示例 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,2,7,4,3]的下一个字典序为[1,3,2,4,7],思考如何转化而来,首先是2和3换了位置[1,3,7,4,2],然后再把3后面的部分翻转就得到了结果。现在问题转化为,如何完成上面两步。1.通过观察得2是反着遍历的第一个i+1大于i的;3是反着遍历第一个大于2的数,找到这两个位置就可以完成第一步的交换。2.接着是翻转操作,把i到len-1的元素全部翻转即可。

  • 还有一种特殊情况:如[7,4,3,2,1]反着遍历没有找到i+1大于i的,此时由题干意思返回[1,2,3,4,7],只需翻转数组返回即可

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        n = len(nums)
        if n <= 1: return
        modify = -1
        # 从后往前寻找非升序数组的第一个元素对应的下标modify
        for i in range(n - 1, -1, -1):
            if i == n - 1: continue
            if nums[i] < nums[i + 1]:
                modify = i
                break
        # 如果modify没变,则此时排列为最大,将数组逆序
        if modify == -1: 
            nums[:] = nums[::-1]
        # 否则
        else: 
            target = -1
            # 找到modify之后比modify大且最接近的元素的下标target
            for i in range(n - 1, modify, -1):
                if nums[i] > nums[modify]: 
                    target = i 
                    break
            # 将modify和target位置的元素交换
            nums[modify], nums[target] = nums[target], nums[modify]
            # 将modify位置之后的元素倒序
            i, j = modify + 1, n - 1
            while i < j:
                nums[i], nums[j] = nums[j], nums[i]
                i, j = i + 1, j - 1
posted @ 2024-01-30 13:01  Frommoon  阅读(2)  评论(0编辑  收藏  举报