给定一个不含重复数字的数组 nums ,返回其所有可能的全排列。你可以按任意顺序返回答案。
回溯法学习
采用深度优先搜索的思想。这个算法能通过尽可能深的方式探索搜索树或者图,进而遍历所有的可能性。该算法采用循环+递归+回撤的方式实现。
个人理解
-
怎么遍历? 从空节点开始,先定排列中第一个元素,也就是循环遍历所有元素(
for循环实现),然后进入访问的第二个元素进行同样的操作。 -
怎么保证不重复访问同一节点?
为每个节点设置访问状态。访问了就修改状态,修改后递归访问第二个节点。 -
怎么实现/回到过去?
修改访问状态+还原进行了的一切操作,这是在递归访问后进行。还原后for循环进行第二个元素的操作,也就是本层搜索树开始进行第二种情况的探索了(相当于平行宇宙)。
写代码bug
pyhon存储列表的时候,是存储列表指针的,而不是列表数据,后面改变了指针的值,会改变所有的,在回溯回起始状态时,指针会变为空,所以result加路径时,要存储列表的副本,可以采用my[:]或者list(my)来实现。
自己的写法
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
length = len(nums)
flag = [0] * length
result = list()
def dfs(height):
if height == length:
#保存每个结果,注意这里是要保存当前my的副本,my是一个引用,后面会修改
result.append(my[:])
return
#遍历每种情况
for i in range(length):
if flag[i] == 0:
my.append(nums[i])
flag[i] = 1
dfs(height+1)
#回撤操作,将原来修改了的变量都取消
flag[i] = 0
my.pop()
my = list()#路径
dfs(0)
return result
改进
在遍历每种情况的时候,每次都对所有元素进行判断有无访问过,使用这种方式有很多重复的操作,那么怎么将未访问过的元素集中起来呢?这样可以除去判断操作。
看题解后,让我想起了类似于排序算法时处理未排序数字的方式,将使用过的元素换到左边,未排序的放到右边。
为什么第一个if后不用return?
因为range(length,length)相当于是空操作,height前都是索引过的值,height后都是待定索引。
class Solution(object):
def permute(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
length = len(nums)
flag = [0] * length
result = list()
def dfs1(height):
if height == length:
#保存每个结果
result.append(nums[:])
#此处可以不用return,因为range(length,length)相当于是空操作
#height前都是索引过的值,height后都是待定索引
for i in range(height,length):
#交换一次,表示这次选择nums[i]
ums[i],nums[height] = nums[height],nums[i]
#下一层
dfs1(height+1)
#撤销原来的操作
nums[i],nums[height] = nums[height],nums[i]
dfs1(0)
return result