题目出自力扣46.全排列和47.全排列Ⅱ。前者给定一个不包含重复数字的序列nums,要求返回所有不重复的全排列;后者在此基础上加上了nums中可包含重复数字的条件。
示例1:
输入:nums=[1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例2:
输入:nums = [1,1,2]
输出:[[1,1,2],[1,2,1],[2,1,1]]
动态规划
假设已经得到含有n个元素的数组的全排列,现再加入一个未出现过的元素x,则x在当前任一排列中的任意位置插入,都能得到一个不同的排列序列。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def insert(arr,num):
res = []
for i in range(len(arr)+1):
temp = arr.copy()
temp.insert(i,num)
res.append(temp)
return res
ans = [[nums[0]]]
i=1
while i < len(nums):
num = nums[i]
subans = []
for a in ans:
subans+=insert(a,num)
ans=subans
i+=1
return ans
但该方法不适合包含重复数字的情况:例如在nums=[1,2,1]时,由[1,2]可得到全排列[[1,2],[2,1]],再插入一个1时会得到[[1,1,2],[1,2,1],[1,2,1],[2,1,1]],出现重复元素[1,2,1]。
回溯
对于有length个元素的数组nums,考虑有length个空格将其填入。在第一个位置填入任一个数后,在剩下的数中选择一个填入下一个空位,直到只剩下最后一个位置未填,得到一个排列。
对于有重复元素的数组,只要将所有数字及其个数进行统计,相同的数字在一轮循环中只填入当前位置一次,就不会造成重复的现象。
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
def fill(first,arr,record):
if first == length-1:
ind = record.index(1)
arr.append(ind-10)
res.append(arr[:])
arr.pop()
return
for i in range(21):
if record[i]!=0:
arr.append(i-10)
record[i]-=1
fill(first+1,arr,record)
record[i]+=1
arr.pop()
record = [0]*21 # 根据题意,nums的范围为[-10,10]
for num in nums:
record[num+10]+=1
res=[]
length = len(nums)
fill(0,[],record)
return res