描述:
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
解题思路:
方法1:回溯法
回溯法的原理在于在前n-1位元素确定的情况下,求取n位以后的全排列。以1,2,3为例,首先固定第0位,就是分别将第0位与它本身及后面各位元素交换,得到3种不同的可能,在固定这一位后,在考虑第1位的可能性,将第1位与它本身及其后元素交换,有两种可能性,当前两位元素确定后,最后一位只有一种可能性。因此一共有6种可能。
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
def backtrack(pos,end):
if pos == end:
res.append(nums[:])
return
for i in range(pos, end):
nums[i], nums[pos] = nums[pos], nums[i]
backtrack(pos + 1, end)
nums[i], nums[pos] = nums[pos], nums[i]
res = []
backtrack(0, len(nums))
return res
方法2:深度优先搜索
推荐啊哈!算法这本算法书,比较直观易理解
(个人理解以及结合啊哈算法中的理解):这题可以简单理解为有n位数字序列,放在n个位置,有多少种放置方案。
以1、2、3为例,对应1,2,3三个位置
实际模拟执行放置:
1、对于第一个位置可以放置1,按照递增的顺序放置数字
2、第2个位置可以放置2,第3个位置可以放置3,产生序列1,2,3
3、接着对于第3个位置,尝试新的放置可能,没有可放置的数字。于是将2号位置的数字回收
4、在第二个位置放置数字3,于是第三个位置此时只能放置2。产生另一序列1,3,2
5、重复以上行为可以得到全排列
从代码层面理解:
每个位置放置所有可能的数字
for i in range(0,len(nums)):
tmp[step] = nums[i]
其中tmp是一个临时数组,对于第step位置,放置第i个数。现在我们考虑另一个问题,对于第i 个数放在了第step的位置,那么就不能放在其他位置了。因此需要一个book数组标记哪些数字已经被放置了。
for i in range(0,len(nums)):
if book[i]:
tmp[step] = nums[i]
book[i] = False
对于第step的位置处理完了,需要考虑step+1的位置。第step+1的位置和step的操作完全相同,因此可以进行封装。其实这里就是一个套娃,会一直嵌套处理step+1的相对下一个位置step+1+1,一直嵌套下去,处理后续位置的数据。
按照实际模拟执行放置:第3步,执行完一趟之后,需要将数字进行回收,才能进行下一趟的操作。
for i in range(0,len(nums)):
if book[i]:
tmp[step] = nums[i]
book[i] = False
dfs(step+1)
book[i] = True
最后需要考虑的是,什么时候得到一个满足条件的序列,即终止条件。当处理完第n个位置的时候,就得到一个满足要求的序列。
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
book = [True for _ in range(len(nums))]
tmp = [i for i in range(len(nums))]
def dfs(step):
if step == len(nums):
res.append(tmp[:])
return
for i in range(0,len(nums)):
if book[i]:
tmp[step] = nums[i]
book[i] = False
dfs(step+1)
book[i] = True
res = []
dfs(0)
return res