每日一题
今天刷的依旧是一道中等题,不过感觉今天这道题是中等难度里面比较难的题了,思考了很长时间。过程感觉比较难以理解。
题目要求
给你一个整数数组 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]]
题目解析
这道题要求求出数组中所有的非递减子序列,我乍一看觉得不难,直接回溯算法感觉就可以解出,但是后面察觉此题并不简单,因为还需要去重,单纯使用最简单的回溯算法不能达到去重的目的,因此还要进行其他的额外的操作进行去重。
首先选出非递增的子序列很简单,如果在回溯选择时如果当前的数大于等于上一个数,就可以被选择加入到回溯的暂时数组中。
重点是如何跨数字选择和如何去重?这里采用两一次递归中要进行两次递归,第一次递归就是上面说的情况,第二次递归是要进行一次判断,每次递归时都会记录下本次操作的数字和上次操作的数字,当这两个数字不相等时则进入第二次递归,第二次递归会不选择当前的数字,直接选择下一个数字,因为两个数如果相等的话跳过当前的数字选择后面的数就是没有意义,这种重复的情况在第一次递归时已经进行了。第二次递归第一次递归结束出来后,从后往前寻找之前没有记录过的组合。因此两数相等时直接跳过,两个数只需要选择一次即可。
代码实现
class Solution {
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public List<List<Integer>> findSubsequences(int[] nums) {
dfs(0, Integer.MIN_VALUE, nums);
return ans;
}
public void dfs(int cur, int last, int[] nums) {
if (cur == nums.length) {
if (temp.size() >= 2) {
ans.add(new ArrayList<Integer>(temp));
}
return;
}
if (nums[cur] >= last) {
temp.add(nums[cur]);
dfs(cur + 1, nums[cur], nums);
temp.remove(temp.size() - 1);
}
if (nums[cur] != last) {
dfs(cur + 1, last, nums);
}
}
}