Leetcode Link: 491. 递增子序列 - 力扣(LeetCode)
题目
给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

本题属于子集问题,不过是有条件的子集问题
解法一
思路:回溯法中的子集问题
显然,本题也同样需要去重,但是不同于子集II,根据本题的要求,本题是不能通过排序进行去重的,因此如果对每一层的子树进行去重,需要用到集合 set() 来完成
满足要求的答案:
len(path)>=2并且path内容非降序
停止回溯的条件:
choose为空
剪枝&去重:
- 当前的值
val在当前层内已经被使用过了 (val in used == True),就continue - 当前值
val放进path后path不再是有序的,continue(实际上是不满足题目要求的剪枝)
题解:
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
def backtracking(choose):
nonlocal res, path
# 用来剪枝&去重
used = set()
# 满足题目条件
if len(path) >= 2:
res.append(copy.deepcopy(path))
# 终止回溯条件
if choose == []:
return
for idx, val in enumerate(choose):
# 剪枝 & 去重
if val in used: # 使用过了
continue
# 剪枝,不满足题目条件不用管
if path != [] and val < path[-1]:
continue
used.add(val) # 用过的,加到used里面
path.append(val)
backtracking(choose[idx+1:])
path.pop()
res = []
path = []
backtracking(nums)
return res复习时遇到了错误,
实际上我也发现同一层需要去重了,但是我的去重手段是 last_num != nums[next_i],并及时更新last_num。然而这种去重方式是错误的
一般用这种方式去重的情况往往是有序的输入,即相同的数字只可能相邻。而在本问题中,相同的数字可能不相邻,所以必须用一个 set() 来筛选
下面贴正确的代码
class Solution:
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
path = [-float('inf')] # 先放一个防止path[-1]报错
res = []
def backtracking(i):
if i >= len(nums):
return
# 题目要求至少俩,所以这里至少仨
if len(path) >= 3:
res.append(path[1:].copy())
used = set()
last_num = -float('inf')
for next_i in range(i+1, len(nums)):
if nums[next_i] not in used and nums[next_i] >= path[-1]:
used.add(nums[next_i])
path.append(nums[next_i])
backtracking(next_i)
path.pop()
backtracking(-1)
return res