给定一个没有重复数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
解题思路
我们首先想到的一个简单的解法,就是通过递归回溯来解。所谓的回溯,无非就是通过暴力破解。这个问题,和之前的问题Leetcode 17:电话号码的字母组合(最详细的解法!!!)很像。因为这个问题中,我们要不断的遍历nums
查看元素在之前的遍历中是不是用过了,如果用过了我们在本次的遍历中就不可以再使用了,否则的话,我们可以使用。所以我们要根据nums
建立一个与之对应的used
,记录我们nums
中的元素是不是用过了。
class Solution:
def _permute(self, nums, p, res, used):
if len(p) == len(nums):
res.append(p.copy())
return
for i,_ in enumerate(nums):
if not used[i]:
p.append(nums[i])
used[i] = True
self._permute(nums, p, res, used)
p.pop()
used[i] = False
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result, used = list(), list()
if not nums:
return result
for _ in enumerate(nums):
used.append(False)
self._permute(nums, list(), result, used)
return result
与这种思想类似,我们还可以这样写
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res, n = list(), len(nums)
def _permute(i):
if i == n:
res.append(nums.copy())
return
for k in range(i, n):
nums[i], nums[k] = nums[k], nums[i]
_permute(i + 1)
nums[i], nums[k] = nums[k], nums[i]
_permute(0)
return res
我稍微提一下这个算法的思路,我们定义函数_permute(i)
表示处理从nums
的i
位置开始的所有全排列。那么我们只需要将第一个数与后面的数交换位置,这样我们就可以得到不同的数开头的去排列,接着递归调用_permute(i+1)
即可得到第一个数之后的所有数的排列结果。
这个问题也可以直接使用递归。如果我们知道了nums[1:]
的全排列结果的话,我们只要将nums[0]
分别插入每个排列的全部位置即可。
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) <= 1:
return [nums]
out = []
perms = self.permute(nums[1:])
for perm in perms:
for i in range(0, len(perm)+1):
p = perm[:i] + [nums[0]] + perm[i:]
out.append(p)
return out
我们使用python
自带的itertools.permutations
可以快速的解决这个问题。
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
import itertools
return list(itertools.permutations(nums))
同样的,对于递归可以解决的问题,我们都应该思考是不是可以通过迭代解决。下面这种写法,参照了itertools.permutations
的实现。
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
result = list()
n = len(nums)
indices = [i for i in range(n)]
cycles = [i for i in range(n, 0, -1)]
result.append([nums[i] for i in indices[:n]])
while n:
for i in reversed(range(n)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
result.append([nums[i] for i in indices[:n]])
break
else:
return result
我主要提一下上面算法使用的思路。首先记录123
,然后交换2
和3
,得到132
,记录132
。然后我们将2
放到list
前,得到213
,记录213
,然后交换1
和3
,得到231
,记录231
。然后我们将3
放到list
前,得到312
,记录312
,然后交换1
和2
,得到321
,记录321
。
上面这种写法有很多优点,但是我更喜欢下面这种实现,完全按照递归的思路来。
class Solution:
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
if len(nums) <= 1:
return [nums]
result = [[nums[0]]]
index = 1
while index < len(nums):
tmp = []
for perm in result:
for i in range(index+1):
tmp.append(perm[:i] + [nums[index]] + perm[i:])
result = tmp
index += 1
return result
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!