今日题目
491.递增子序列
题目链接:491. 非递减子序列 - 力扣(LeetCode)
思考:本题给出的数组已经是递增顺序,数组元素存在重复,且在一个结果中可以出现两个相同元素作为递增序列,因此在遍历树结构时,同一层级需要元素去重,这里采用集合记录元素使用情况。其余部分采用递归+回溯思想实现。
代码:
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
ans = []
path = []
def dfs(nums, start, path, ans):
if len(path) > 1:
ans.append(path[:])
use_set = set()
for i in range(start, len(nums)):
if (path and nums[i] < path[-1]) or nums[i] in use_set:
continue
use_set.add(nums[i])
path.append(nums[i])
dfs(nums, i+1, path, ans)
path.pop()
dfs(nums, 0, path, ans)
return ans
46.全排列
思考:本题要返回数组的全排列,因此在遍历树结构得到的每一个path长度都与原始数组相同,遍历完数组所有元素程序终止。这里也要求元素不能重复使用,因此在遍历过一个元素后需要在去掉该元素的剩余元素中遍历,故也可以采用上一题的思想,用集合记录元素使用情况。
这里采用优化方案,使用集合操作 s - {x}
高效移除已用元素,确保排列不重复使用数字。相比标记数组更节省空间。
每次递归传入新的集合 s - {x}
,无需显式回溯状态。path[i]
会被后续选择覆盖,自然实现回溯。
代码:
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
ans = []
path = [0] * n
def dfs(i,s):
if i == n:
ans.append(path.copy())
return
for x in s:
path[i] = x
dfs(i+1, s - {x})
dfs(0, set(nums))
return ans
47.全排列 II
题目链接:
思考:上一题全排列没有重复元素,采用集合记录可选元素,每次选取一个元素后集合就剔除该元素。本题数组中存在重复元素,可以考虑记录元素的下标使用情况。
这种情况需要首先对数组排序,然后处理存在相等的元素的情况下,只用一个。在递归和回溯时要同时处理path和used。
代码:
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
nums.sort()
ans = []
path = []
used = [False] * n
def dfs(nums, used, path, ans):
if len(path) == n:
ans.append(path[:])
return
for i in range(n):
if (i > 0 and nums[i] == nums[i-1] and not used[i-1]) or used[i]:
continue
used[i] = True
path.append(nums[i])
dfs(nums, used, path, ans)
path.pop()
used[i] = False
dfs(nums, used, path, ans)
return ans