全排列問題
0. 參考文獻
序號 | 文獻 |
---|---|
1 | 全排列算法part1 |
2 | 全排列算法part2 |
3 | 全排列算法的全面解析 |
4 | 一次搞懂全排列——LeetCode四道Permutations問題詳解 |
在LeetCode中一共有4個和全排列相關的題目分別是:
題號 | 題目 |
---|---|
31 | Next Permutation |
46 | Permutations |
47 | Permutations II |
60 | Permutation Sequence |
本文記錄下在刷題過程中對於這個類題型的解法,希望對大家有所幫助。
1. 遞歸解法
對於全排列的求解,第一個想到的肯定是通過遞歸的解法。例如對於數列p(n)={1,2,3,…,n},從中間取出一個數比如1,剩下的只需要求出p(n-1)的全排列,然后依次把1加入p(n-1)的全排列中。對於全排列也有2中方法:
- 將取出的數(例子中是1),依次插入到p(n-1)的全排列的不同位置上。在這里稱之為插入法。
- 首元素依次和后續的元素交換,然后求首元素之后的子序列的全排列。這里稱之為首元素固定法。
相信對於2個方法的描述,大家應該還是比較模糊的。沒關系后續將會詳細講解。
1.2 插入法
舉個例子,比如{1, 2 , 3 },我們知道這個序列的全排列是:
{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以外剩下的元素的全排列。
因此可以總結出如下的步驟:
- 將首元素摘出來
- 生成剩余序列的全排列
- 將首元素插入步驟2中的序列的各個位置
實現的代碼如下:
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。例如圖中是元素2
- 再從序列尾部開始,找到第一個比替換點1大的元素,這里稱之為替換點2。例如圖中是元素3
- 交換替換點1和2
- 從替換點1下一個元素開始,到序列尾部,所有元素反正
上面的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