491. 非递减子序列-day30-回溯

给你一个整数数组 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]]
解答:参考storm大神做法
用 n 表示数组 nums 的长度。生成数组 nums 的子序列可以使用回溯实现。这道题要求生成所有的至少有两个元素的不同递增子序列,即存在如下限制。
子序列至少有两个元素。
子序列中的元素递增。
答案不重复。如果存在两个相等的子序列,则只能添加到答案一次。
如果没有任何限制,则在回溯过程中不需要有任何剪枝操作,生成所有子序列即可。回溯的思路如下:从左到右遍历数组 nums,每个元素都可以加入子序列或不加入子序列,分别对两种情况继续遍历后续元素,当遍历数组结束时即得到一个子序列,将该子序列添加到答案。
当存在上述限制时,需要对不符合要求的情况剪枝。做法如下。
子序列至少有两个元素。当遍历数组结束时,需要检查子序列中的元素个数,只有在子序列中至少有两个元素的情况下才将子序列添加到答案。
子序列中的元素递增。对于遍历到的每个元素,需要比较该元素与上一个添加到子序列的元素,只有在当前元素大于等于上一个添加到子序列的元素的情况下才可以将当前元素添加到子序列。
答案不重复。为了避免答案重复,需要考虑可能产生重复答案的原因,产生重复答案的原因是:如果同一个元素值在数组中出现 x 次,该元素值在子序列中出现 y 次,满足 x>y>0,则从 x 个该元素值中选择 y 个元素的不同方案可能产生相同的子序列。一种避免答案重复的方法是在跳过元素(即元素不加入子序列)时剪枝,只有在当前元素不等于上一个添加到子序列的元素的情况下才可以将当前元素跳过。该剪枝方法可以确保当存在多个相同值的元素时,所有跳过的元素都是最前面的元素,因此不会出现重复考虑选择相同数量元素的不同方案的情况,因此不会出现重复。
`
class Solution {
List<List> subsequences = new ArrayList<List>();
List temp = new ArrayList();
int[] nums;
int n;
public List<List> findSubsequences(int[] nums) {
this.nums = nums;
this.n = nums.length;
backtrack(0, Integer.MIN_VALUE);
return subsequences;
}
public void backtrack(int index, int prev) {
if (index == n) {
if (temp.size() >= 2) {
subsequences.add(new ArrayList(temp));
}
} else {
if (nums[index] >= prev) {
temp.add(nums[index]);
backtrack(index + 1, nums[index]);
temp.remove(temp.size() - 1);
}
if (nums[index] != prev) {
backtrack(index + 1, prev);
}
}
}
}

`

posted @ 2026-03-24 10:21  大头海绵宝宝  阅读(1)  评论(0)    收藏  举报