1. 题目解析与核心挑战
Leetcode 491题"非递减子序列"是一道典型的中等难度回溯算法问题。题目要求给定一个整数数组nums,找出所有不同的非递减子序列,且子序列长度至少为2。这里的非递减子序列指的是序列中每个元素都不小于前一个元素。
这道题的核心难点在于:
- 如何高效生成所有可能的子序列
- 如何避免重复子序列的产生
- 如何确保子序列满足非递减条件
与普通的子集问题不同,本题对子序列的顺序和元素相对大小有严格要求,这增加了问题的复杂度。我在实际解题过程中发现,很多初学者容易陷入暴力枚举的陷阱,导致时间复杂度过高或者无法正确处理重复序列的问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法思路与方案选型
2.1 回溯算法基础框架
回溯法是解决这类问题的经典方法。基本思路是通过递归尝试所有可能的组合,并在递归过程中进行剪枝优化。对于本问题,回溯算法的框架可以这样构建:
- 定义一个结果列表存储所有符合条件的子序列
- 定义一个临时列表存储当前递归路径上的元素
- 在递归过程中,对每个元素做出选择或不选择的决定
- 添加适当的条件判断进行剪枝
2.2 关键优化点分析
在实际编码中,我发现有几个关键点需要特别注意:
-
去重处理:由于数组中可能存在重复元素,直接回溯会产生重复子序列。常见的错误做法是在最后对结果去重,这样会显著增加时间复杂度。
-
非递减判断:需要在选择元素时立即判断是否满足非递减条件,而不是等到子序列完整生成后再判断。
-
剪枝策略:当当前元素小于子序列最后一个元素时,应该跳过该元素的选择,这可以避免无效的递归路径。
3. 详细实现与代码解析
3.1 完整Python实现
python复制def findSubsequences(nums):
result = []
path = []
def backtrack(start):
if len(path) >= 2:
result.append(path[:])
used = set() # 用于本层去重
for i in range(start, len(nums)):
if nu
