78. 子集
这道题和前几题有些不一样,前几题都是有条件的收集路径path。比如对路径path的大小加一限制,或者对路径path的和加以限制。但是在这道题中对路径path没有任何限制,只需要我们在取出一个值后,将值输入result中,再从剩余元素中取一值,不断递归回溯。
class Solution {
private:
vector
vector
void backtracking(vector
{
//将path赋值给result时不需要加任何限制
result.push_back(path);
//每个for循环都是在遍历同一层
for(int i=startIndex;i { path.push_back(nums[i]); backtracking(nums,i+1); path.pop_back(); } } public: vector backtracking(nums, 0); return result; } }; 90. 子集 II 这道题和力扣第40题类似,都需要对数组进行排序后,修剪掉同层的相同元素,保证组合不重复。 那什么时候是在遍历同层元素呢?当i>startIndex时就是在遍历同层元素。可以看看我上篇文章第40题的解析,可以了解到什么在遍历同层、什么时候在遍历同枝。 class Solution { public: vector vector void backtracking(vector { ans.push_back(path); for(int i=startIndex;i { //去掉同层相同的元素 if(i>startIndex && nums[i]==nums[i-1]) continue; path.push_back(nums[i]); backtracking(nums,i+1); path.pop_back(); } } vector sort(nums.begin(),nums.end()); backtracking(nums,0); return ans; } }; 491. 递增子序列 这题也是从集合中不断取值,题目要求结果不能出现重复的集合,所以要进行去重操作。但是这题的去重和前几题又有一些不同,前面都是可以先排序然后再去重。这题要求返回子序列,排序后子序列就改变了,所以不能排序。需要同层去重,如果我们可以记录同一层中哪些元素已经使用过了,然后再遍历新的元素时查看该元素的值是否被使用过。那么问题就解决了。 于是我们用一个集合来记录哪些元素已经使用过了 class Solution { public: vector vector void backtracking(vector { if(path.size()>=2) ans.push_back(path); unordered_set for(int i=startIndex;i { if(path.size()>0 && nums[i] //如果该值在used集合中出现过,表示它已经被使用过了,舍弃 //find(key)函数如果没找到键值key会返回迭代器end if(used.find(nums[i])!=used.end()) continue; path.push_back(nums[i]); used.insert(nums[i]); backtracking(nums,i+1); path.pop_back(); } } vector backtracking(nums,0); return ans; } }; !!!错误代码 class Solution { public: vector vector unordered_set void backtracking(vector { if(path.size()>=2) ans.push_back(path); used.clear();//used设为全局变量导致这里清空的话,那上一层的记录也全部被清空了,used变量将毫无作用,等于没写 for(int i=startIndex;i { if(path.size()>0 && nums[i] //如果该值在used集合中出现过,表示它已经被使用过了,舍弃 //find(key)函数如果没找到键值key会返回迭代器end if(used.find(nums[i])!=used.end()) continue; path.push_back(nums[i]); used.insert(nums[i]); backtracking(nums,i+1); path.pop_back(); } } vector backtracking(nums,0); return ans; } }; 46. 全排列 这道题是排列,排列和组合不一样。排列有序,组合无序。比较简单的思路就是当取出一个元素后,我们就将这个元素移除,然后再剩余的元素中再取值,直到没有剩余的元素了。 class Solution { public: vector vector void backtracking(vector { if(nums.empty()) { ans.push_back(path); return; } for(int i=0;i { path.push_back(nums[i]); //移除取过的元素 vector temp.erase(temp.begin()+i); backtracking(temp); path.pop_back(); } } vector backtracking(nums); return ans; } }; 第二种方法是用一个数组来记录已经已经使用过的元素 class Solution { public: vector vector void backtracking(vector { if(path.size()==nums.size()) { ans.push_back(path); return; } for(int i=0;i { if(used[i]==true) continue; path.push_back(nums[i]); //标记使用过的元素 used[i]=true; backtracking(nums,used); path.pop_back(); used[i]=false; } } vector vector backtracking(nums,used); return ans; } }; 47. 全排列 II 相较于上一题,这题多了一步去重的操作。我们可以在排序后直接用used进行同层去重,和之前的题目一样,如果前一个元素的used值为false,说明两个元素处于同层。 class Solution { public: vector vector void backtracking(vector { if(path.size()==nums.size()) { ans.push_back(path); return; } for(int i=0;i { //同层去重 if(i>0 && used[i-1]==false && nums[i]==nums[i-1]) continue; //这个是对自己进行去重,防止再取到自己 if(used[i]==true) continue; path.push_back(nums[i]); //标记使用过的元素 used[i]=true; backtracking(nums,used); path.pop_back(); used[i]=false; } } vector sort(nums.begin(),nums.end()); vector backtracking(nums,used); return ans; } }; 相关链接
发表评论