题目描述
给你一个整数数组 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]]
思路
- 画出抽象树
- 乍一看,本题感觉与
子集II十分相似,但使用子集II的思路却不行,这是因为 子集II的去重操作的前提是先对数组进行排序,本题却不能先进行排序,因为我们要得到的是所有递增的子序列 - 需要进行处理的情况:
- 长度必须大于2
- 序列必须是递增
- 去重逻辑:
树层去重,每次递归单独设置一个Map结构存放本层元素的使用情况。
代码
function findSubsequences(nums: number[]): number[][] {
let result=[],path=[];
//回溯方法
function backtracking(nums: number[],startIndex:number):void{
// 终止条件
if(startIndex==nums.length){
return;
}
// 存放同一层元素元素是否使用过
let used=new Map();
for(let i=startIndex;i<nums.length;i++){
// 如果元素没使用过
if(!used.get(nums[i])){
// push进used数组
path.push(nums[i]);
// 判断是否是递增数组吗,若是
if(isIncreasing(path)){
//记录该数使用过
used.set(nums[i],true)
// 收割结果
if(path.length>1){
result.push([...path]);
}
// 递归调用
backtracking(nums,i+1);
// 回溯操作
path.pop();
}else{
// 如果path 不是一个递归数组,则直接将push进去的数弹出,进行下一次循环。
path.pop();
}
}else{
continue;
}
}
}
// 判断是否是递增函数
function isIncreasing (nums: number[]):Boolean{
for(let i=1;i<nums.length;i++){
if(nums[i]<nums[i-1]) return false;
}
return true;
}
backtracking(nums,0)
return result
};
总结
子序列与子集问题不同点在于:子序列内部是有一定的顺序的,而子集不在意内部顺序。所以这也是子集问题可以先排序再去重,而子序列问题不能这样做的原因。