递增子序列(一个完美的题型,解释很多)
说明
- 这个题型说明了很多问题,首先是startIndex的使用
- 其次是同一数层的去重,和前面的去重还不一样,因为原数组是不能排序的
- 还有什么时候应该在终止条件中return
题目
给你一个整数数组 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
思路
思路于代码中,注意!path.empty() && nums[i] < path.back()的顺序不能反。
代码
// 输入: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]]
//子数列,又称子序列,在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下
//元素的相对位置(在前或在后)而形成的新序列,注意是不能通过破坏原有数组的相对顺序的,所以
//不能对原数组进行排序,这个是最重要的一点
//那么没有排序的原数组怎么去重呢,要对同一层的所有元素使用unordered_set进行去重
class Solution {
private:
vector<int> path;
vector<vector<int>> result;
void backing(vector<int>& nums, int startIndex) {
if(path.size() >= 2) {
result.push_back(path);
//return;//如果返回的话那么就是一个回溯的过程,无法往下取
}
unordered_set<int> usedSet;
for (int i = startIndex; i < nums.size(); i++) {
//判断什么时候应该看看这个元素是不是应该进入path
//首先如果path内部没有元素,那么直接收录nums[i]
//如果这个nums[i]比path最后一个元素还要小的话,那么path不用收录
//如果这个元素已经使用过那么path也不用收录
//综上所述,那么什么情况下需要跳过呢
//(1):path不是空的而且path的最后一个元素要比nums[i]大
//(2):这个元素已经在同一层当中使用过了
//注意!path.empty() && nums[i] < path.back()的顺序不能反
if((!path.empty() && nums[i] < path.back()) || usedSet.find(nums[i]) != usedSet.end()){
continue;
}
usedSet.insert(nums[i]);
path.push_back(nums[i]);
backing(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
backing(nums, 0);
return result;
}
};

浙公网安备 33010602011771号