非递减子序列
难度:
标签:
题目描述
给你一个整数数组 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
代码结果
运行时间: 63 ms, 内存: 21.9 MB
/*
* 思路:
* 使用Java Stream API进行递归,通过维护一个列表来构建递增子序列。
* 使用set去重,确保序列的唯一性。
*/
import java.util.*;
import java.util.stream.Collectors;
public class Solution {
public List<List<Integer>> findSubsequences(int[] nums) {
Set<List<Integer>> result = new HashSet<>();
List<Integer> tempList = new ArrayList<>();
findSequences(result, tempList, nums, 0);
return result.stream().collect(Collectors.toList());
}
private void findSequences(Set<List<Integer>> result, List<Integer> tempList, int[] nums, int start) {
if (tempList.size() > 1) {
result.add(new ArrayList<>(tempList));
}
Arrays.stream(nums, start, nums.length).forEach(i -> {
if (tempList.isEmpty() || tempList.get(tempList.size() - 1) <= nums[i]) {
tempList.add(nums[i]);
findSequences(result, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
});
}
}
解释
方法:
这个题解使用回溯法来找到所有不同的递增子序列。具体思路为:
1. 定义path数组保存当前选择的子序列,res数组保存所有合法的递增子序列。
2. 使用traceback函数进行回溯,参数为原数组nums和当前选择元素的起始下标startindex。
3. 终止条件为startindex等于nums长度,即所有元素都已遍历。
4. 在选择列表中依次选择当前下标i对应的元素:
- 如果path非空且当前元素小于path最后一个元素,或者当前元素已经在本层选择过,则跳过避免重复。
- 否则将当前元素加入path,并用哈希表记录已选择过的元素。
- 进入下一层递归,下标为i+1。
- 递归返回后,从path中删除当前元素,进行回溯。
5. 在递归前,如果path长度大于1,则找到一个合法的递增子序列,将其加入res。
6. 原问题的解即为res数组。
时间复杂度:
O(2^n)
空间复杂度:
O(n * 2^n)
代码细节讲解
🦆
在回溯算法中,如何确保生成的子序列是递增的?特别是当遇到相等的元素时,这一点如何处理?
▷🦆
在处理具有相同元素的数组时,算法是如何避免重复生成相同子序列的?具体是通过哪种机制或数据结构实现的?
▷🦆
为什么在递归的每一层中初始化一个新的哈希表来记录已选择的元素,而不是在全局维护一个哈希表?这样做的好处是什么?
▷🦆
算法中提到如果`path`长度大于1,则视为找到一个合法的递增子序列并加入到`res`数组中。这种方法是否可能导致在递归过程中多次添加同一个子序列?
▷相关问题
最长数对链
给你一个由 n
个数对组成的数对数组 pairs
,其中 pairs[i] = [lefti, righti]
且 lefti < righti
。
现在,我们定义一种 跟随 关系,当且仅当 b < c
时,数对 p2 = [c, d]
才可以跟在 p1 = [a, b]
后面。我们用这种形式来构造 数对链 。
找出并返回能够形成的 最长数对链的长度 。
你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
示例 1:
输入:pairs = [[1,2], [2,3], [3,4]] 输出:2 解释:最长的数对链是 [1,2] -> [3,4] 。
示例 2:
输入:pairs = [[1,2],[7,8],[4,5]] 输出:3 解释:最长的数对链是 [1,2] -> [4,5] -> [7,8] 。
提示:
n == pairs.length
1 <= n <= 1000
-1000 <= lefti < righti <= 1000