2020年5月10日 星期日

Leetcode題解 Python:Next Permutation

給一個組合,要回傳(按各組合由小到大)下一個組合,如果是最大的組合,則回傳最小的組合。

這一題是一種數學題,如果數學想通了就很好解,沒想通,那就只好琢磨到理解為止。

這裡要講如何理解。以 [4,2,3,1] 排組為例。

如果要找到下一個,就只要從右方移一個(從尾開始),讓該組合的大小略增即可。

那要跟誰換呢?從右方開始,如果該位置的值比左方的大,那就是目標位置。
如果左方皆 >= 右方,那代表該組合是最大的。如 [4,3,2,1] [5,1,1]
([4,【2,3】,1])※選左右哪方當目標位置都可以。這裡用左右,必免混淆。

接著從目標位置右及右方開始選一個大於目標位置左的最小值,二者互相交換。可以想成進位。
([4,【2(左),3(右)】,1] -> [4,2,【3,1】] -> [4,2,【3】,1] -> [4,3,2,1])

換完之後,目標位置右方,應該要變成小到大的排序﹐才會是下一個組合。
([4,【3】,2,1] -> [4,3,1,2])

在換之前,目標位置右及右方已經是非升序排列(左>=右),若把它看成一個排列組合,那此時的右方排列會是該排列組合中最大的。

最大的組合,只要反序,就會回到最小的組合。

若碰到 [4,3,2,1],目標位置會在 4 的前方,沒辦法交換,所以直接把數列反序即可。

而交換之後,右方的非升序排列的性質依舊不變,因此只要把右方反序,就會變成右方最小的組合。

反序之後的組合就是題目所求。


流程

Python
class Solution:
    def nextPermutation(self, nums) -> None:
        n = len(nums)
        si = n - 1
        while si > 0 and nums[si] <= nums[si-1]:
            si -= 1
        while si:
            for j in range(n-1, si-1, -1):
                if nums[j] > nums[si-1]:                    
                    nums[si-1], nums[j] = nums[j], nums[si-1] 
                    nums[si:] = nums[si:][::-1]
                    return
            si -= 1
        nums[si:] = nums[si:][::-1]