3道题目
491. 递增子序列
46. 全排列
47. 全排列 II
解题理解
491
一开始我以为是以前那道去重的题,后来看到示例2发现不能对原数组进行排序。所以这道题不能以树层去重思路去写,可以借用集合去去重。
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
path = []
res = []
self.backtracking(nums, 0, path, res)
return res
def backtracking(self, nums, start, path, res):
if len(path) > 1:
res.append(path[:])
//这里不需要return,因为不是在收集叶子节点
uset = set()
for i in range(start, len(nums)):
if (path and nums[i] < path[-1]) or nums[i] in uset:
continue
//nums[i] < path[-1]保证加进来的都是大于当前最大值的新值
uset.add(nums[i])
path.append(nums[i])
self.backtracking(nums, i + 1, path, res)
path.pop()
46
这道题需要遍历整棵树,所以终止条件在于到达子节点,同时为了把尽可能多的结点加入结果集,同时不重复加入,就需要多设置一个标记数组,该数组记录结点有没有被加入过结果集,而且在搜寻结果集时,每次都需要从头找,所以不需要之前一直用的start。
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
path = []
res = []
used = [False] * len(nums)
self.backtracking(nums, path, res, used)
return res
def backtracking(self, nums, path, res, used):
if len(path) == len(nums):
res.append(path[:])
return
for i in range(len(nums)):
if used[i]:
continue
used[i] = True
path.append(nums[i])
self.backtracking(nums, path, res, used)
path.pop()
used[i] = False
47
这道题跟前一道题最大的不同点在于有重复数字,且需要去重,所以就可以继续使用之前用过的排序后再回溯。
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
nums.sort()
path = []
res = []
used = [False] * len(nums)
self.backtracking(nums, path, res, used)
return res
def backtracking(self, nums, path, res, used):
if len(path) == len(nums):
res.append(path[:])
return
for i in range(len(nums)):
if (i and nums[i] == nums[i - 1] and not used[i - 1]) or used[i]:
continue
//nums[i] == nums[i - 1] and not used[i - 1]是为了树层去重,即在同一层中不能有重复的元素,这样就能在回溯过程中起到去重的作用,反映在叶子节点上就是没有重复的全排列组合
used[i] = True
path.append(nums[i])
self.backtracking(nums, path, res, used)
path.pop()
used[i] = False