题目:491. 非递减子序列
给你一个整数数组 nums
,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
示例 1:
输入:nums = [4,6,7,7] 输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
示例 2:
输入:nums = [4,4,3,2,1] 输出:[[4,4]]
提示:
1 <= nums.length <= 15
-100 <= nums[i] <= 100
一、模式识别
1.子集问题
子集问题是边访问边收集结果,
不仅在回溯树叶节点收集结果,
因此return和收集结果命令不在一起
2.搜索集
单独搜索集,
无重复选取,但可能含有重复元素
终止条件是最简单的访问到终点
3.结果收集条件
结果收集比较特殊,
需要递增序列
且至少两个元素
递增序列可以在实现路径过程中形成,不需要写在结果收集条件中
因此有在结果收集条件体现只少两个元素:
if len(path) >= 2:
ans.append(path[:])
在path形成过程中剪去非递增的路径(并配合同层去重):
if (path and ch < path[-1]) or ch in uset:
continue
二.代码实现
本题只能基于数值哈希去重
used数值集合(set):
class Solution:
def backtracking(self, nums, start_idx, path, ans):
if len(path) >= 2:
ans.append(path[:])
if start_idx == len(nums):
return
uset = set()
for i in range(start_idx, len(nums)):
ch = nums[i]
if (path and ch < path[-1]) or ch in uset:
continue
path.append(nums[i])
uset.add(ch)
self.backtracking(nums, i + 1, path, ans)
path.pop()
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
ans = []
# nums.sort()
self.backtracking(nums, 0, [], ans)
return ans
used数值数组(list):
class Solution:
def backtracking(self, nums, start_idx, path, ans):
if len(path) >= 2:
ans.append(path[:])
if start_idx == len(nums):
return
used = 201 * [False]
for i in range(start_idx, len(nums)):
ch = nums[i]
if (path and ch < path[-1]) or used[ch + 100]:
continue
path.append(nums[i])
used[ch + 100] = True
self.backtracking(nums, i + 1, path, ans)
path.pop()
def findSubsequences(self, nums: List[int]) -> List[List[int]]:
ans = []
# nums.sort()
self.backtracking(nums, 0, [], ans)
return ans
三、为什么本题不排序也能去重?
1.原因
先直接给结论:因为递增序列的结果收集条件已经实现了异层去重
在上个刷题记录中思考了排序的两重作用,
因此虽然本题题目要求不能排序
但只保留递增的path的条件保证了path中已经存在的元素不会在path中再次访问
因此只需要同层去重就可以实现去重
因此也就保证了后面的层
2.以后遇到不能排序的情况怎么办?
了解了排序的两重作用大致的解法很明显了
数值哈希 + 某种异层去重的方法
具体的方法需要根据情况,
但有了大致的思考方向遇到新题一脸懵的概率就小了很多