491.递增子序列
思路:代码随想录
思路:本题跟子集2不一样,无法排序,也就是在去重上我们无法使用bool数组来去重,所以本题我们要使用set来去重。三部曲:
- 递归函数参数
本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置。
代码如下:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex)
终止条件:
题目要求递增子序列大小至少为2 所以 path.size()>1。终止条件跟子集问题一样,我们需要遍历整棵树,所需不需要写。
单层递归逻辑。
for循环外定义一个set。循环取数,如果当前path不为空且你取得这个值比path最右边的值小或当前取得数在set中有。就continue。
取过的数加入set。
unordered_set<int> uset;
for(int i = startindex;i<nums.size();i++){
if((!path.empty()&&nums[i]<path.back())|| uset.find(nums[i]) != uset.end()){
continue;
}
uset.insert(nums[i]);
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
46 全排列
思路:代码随想录
思路:排列问题跟组合问题不一样的点是:i 从0开始遍历而不是startindex,因为排列可以取前面的元素比如说【1,2】,【2,1】是2个排列。此外我们还需要used数组来避免一个元素取两次。终止条件:我们在叶子节点收集结果,所以当path.size() == nums.size()时 就收集结果
for (int i = 0; i < nums.size(); i++) {
if (used[i] == true) continue; // path里已经收录的元素,直接跳过
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = false;
}
全排列2
思路: 代码随想录
思路:本题在上一题基础上有重复元素,要去重使用used 数组来去重
void backtracking (vector<int>& nums, vector<bool>& used) {
// 此时说明找到了一组
if (path.size() == nums.size()) {
result.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
// used[i - 1] == true,说明同一树枝nums[i - 1]使用过
// used[i - 1] == false,说明同一树层nums[i - 1]使用过
// 如果同一树层nums[i - 1]使用过则直接跳过
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
continue;
}
if (used[i] == false) {
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = false;
}
}
}
为什么要if(used[i]==false)才执行取数操作呢,为了防止重复取数。因为used数组会标记取过的数。而for循环是从0开始的,所以需要这一步。