全排列問題

全排列問題

0. 參考文獻

序號 文獻
1 全排列算法part1
2 全排列算法part2
3 全排列算法的全面解析
4 一次搞懂全排列——LeetCode四道Permutations問題詳解

在LeetCode中一共有4個和全排列相關的題目分別是:算法

題號 題目
31 Next Permutation
46 Permutations
47 Permutations II
60 Permutation Sequence

本文記錄下在刷題過程當中對於這個類題型的解法,但願對你們有所幫助。app

1. 遞歸解法

對於全排列的求解,第一個想到的確定是經過遞歸的解法。例如對於數列p(n)={1,2,3,…,n},從中間取出一個數好比1,剩下的只須要求出p(n-1)的全排列,而後依次把1加入p(n-1)的全排列中。對於全排列也有2中方法:.net

  1. 將取出的數(例子中是1),依次插入到p(n-1)的全排列的不一樣位置上。在這裏稱之爲插入法。
  2. 首元素依次和後續的元素交換,而後求首元素以後的子序列的全排列。這裏稱之爲首元素固定法。

相信對於2個方法的描述,你們應該仍是比較模糊的。不要緊後續將會詳細講解。code

1.2 插入法

舉個例子,好比{1, 2 , 3 },咱們知道這個序列的全排列是:blog

{1,2,3}
{1,3,2}
{2,1,3}
{2,3,1}
{3,1,2}
{3,2,1}排序

觀察上面的結果,能夠發現只要把1插入到{2,3}和{3,2}的各個位置,就能夠得到答案。同時也能夠知道{2,3}和{3,2}實際上是除了1之外剩下的元素的全排列。遞歸

所以能夠總結出以下的步驟:get

  1. 將首元素摘出來
  2. 生成剩餘序列的全排列
  3. 將首元素插入步驟2中的序列的各個位置

實現的代碼以下:it

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if len(nums) == 0 : return [[]]
        ret = []
        sub_permute = self.permute(nums[1:])
        for e in sub_permute:
            
            for (index,x) in enumerate(e):
                t = list(e)
                t.insert(index,nums[0])
                ret.append(t)
                
            t = list(e)
            t.append(nums[0])
            ret.append(t)
        return ret

1.3 首元素固定法

繼續上面那個例子{1,2,3}:

{1,2,3}
{1,3,2}
{2,1,3}
{2,3,1}
{3,1,2}
{3,2,1}

是否發現生成全排列的方式也能夠固定一個首元素,而後生成剩下的元素的排列,再將1和剩下的元素的排列作組合。

例如固定1 ,而後生成{2,3}的全排列是{2,3}和{3,2}。而後1和{2,3}和{3,2}組合。而後交換1和2 ,讓2作首元素,在生成{1,3}的全排列{1,3}和{3,1},在和2作組合。實現的代碼以下:

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        return self.p(nums)
        
    def p(self,nums):
        
        if len(nums) == 1 :
            return [[nums[0]]]
        
        ret = []
        for i in range(len(nums)):
            nums[0],nums[i] = nums[i],nums[0]
            t = self.p(nums[1:])

            for e in t :
                t1 = list(e)
                t1.insert(0,nums[0])
                ret.append(t1)
            nums[0],nums[i] = nums[i],nums[0]
        return ret

2. 字典序法

這裏直接引用文獻3全排列算法的全面解析中的圖來講明下字典序的方法。以下圖所示:

  1. 而後從序列尾部開始,找到第一個開始降序的元素,稱之爲替換點1。例如圖中是元素2
  2. 再從序列尾部開始,找到第一個比替換點1大的元素,這裏稱之爲替換點2。例如圖中是元素3
  3. 交換替換點1和2
  4. 從替換點1下一個元素開始,到序列尾部,全部元素反正

dp

上面的4步既是求出了當前序列的下一個比它大的序列。所以,求一個序列的全排序,能夠從序列的最小排列開始,一直求到最大排列,既求得了全排列。

代碼實現以下:

class Solution(object):
    def islast(self,nums):
        for i in range(0,len(nums) - 1):
            if nums[i]<nums[i+1]:
                return False
        return True
    def permuteUnique(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        ret =  []
        nums.sort()
        tmp = list(nums)
        ret.append(tmp)
        first_index = 0
        sec_index = 0
        j = 0
        while True :
            if self.islast(nums) == True:
                break

            for i in range(len(nums) - 2 , -1 ,-1):
                if nums[i]<nums[i+1]:
                    first_index = i
                    break
            for i in range(len(nums)-1, first_index, -1 ):
                if nums[i] > nums[first_index] :
                    sec_index = i
                    break
            nums[first_index],nums[sec_index] = nums[sec_index],nums[first_index]
            for i in range(first_index+1,len(nums)):
                if i<=len(nums) - 1 - (i-first_index-1):
                    nums[i],nums[ len(nums) - 1 - (i-first_index-1) ] = nums[ len(nums) - 1 - (i-first_index-1) ],nums[i]

            tmp = list(nums)
            ret.append(tmp)
            first_index = 0
            sec_index = 0
        return ret
相關文章
相關標籤/搜索