#491 递增子序列 有点难 30min 找不到合适的去重逻辑了,于是没办法用了set
“90子集ii 中我们是通过排序,再加一个标记数组来达到去重的目的。 而本题求自增子序列,是不能对原数组进行排序的,排完序的数组都是自增子序列了。 所以不能使用之前的去重逻辑!”
用[4, 7, 6, 7] 或者 [4,6,7,5,7] 都能体现这个题的特点,正确的逻辑是:同一父节点下的同层上使用过的元素就不能再使用了
然后本来想用 unordered_set
我的code:用set的,comment掉的是走不通的去重逻辑
set> res;
vector vec;
void backtrack(int startIdx, vector& nums){
if(startIdx>=nums.size()) return;
for(int i=startIdx; i=2) res.insert(vec);
backtrack(i+1,nums);
vec.pop_back();
}
}
vector> findSubsequences(vector& nums) {
res.clear();
vec.clear();
backtrack(0,nums);
vector> result(res.begin(), res.end());
return result;
}
根据随想录修改过后的:其实就是加了个unordered_set
学到了vec最后一个元素可以直接用.back()
set> res;
vector vec;
void backtrack(int startIdx, vector& nums){
if(startIdx>=nums.size()) return;
unordered_set uset; // 使用set来对本层元素进行去重
for(int i=startIdx; i=2) res.insert(vec);
backtrack(i+1,nums);
vec.pop_back();
}
}
vector> findSubsequences(vector& nums) {
res.clear();
vec.clear();
backtrack(0,nums);
vector> result(res.begin(), res.end());
return result;
}
#46 全排列 25min, 主要就是去重
弄了一个set去重,但是一开始没写对,在push 到 res那里就直接clear了,结果WA,一个个print出来发现不对,set也应该加入回溯
一个个print debug真的有点慢的,尤其是写print还不熟练的时候,比如print set:用for auto ele:set 就行
vector> res;
vector vec;
set used;
void backtrack(vector& nums){
if(vec.size()==nums.size()){
res.push_back(vec);
return;
}
for(int i=0;i> permute(vector& nums) {
backtrack(nums);
return res;
}
啊其实改了一下发现很容易,没什么怕错的:然后我的set当做 global var因为我有点怕放在传参数那里会传错,但是还是要练一下再写一版。然后随想录和我的区别就是不用的set,用的是
vector used(nums.size(), false);
vector> res;
vector vec;
void backtrack(vector& nums, set used){
if(vec.size()==nums.size()){
res.push_back(vec);
return;
}
for(int i=0;i> permute(vector& nums) {
set used;
backtrack(nums,used);
return res;
}
下面也放一下随想录的46代码,这样47题看总结时可以参考
vector> result;
vector path;
void backtracking (vector& nums, vector& used) {
// 此时说明找到了一组
if (path.size() == nums.size()) {
result.push_back(path);
return;
}
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;
}
}
vector> permute(vector& nums) {
result.clear();
path.clear();
vector used(nums.size(), false);
backtracking(nums, used);
return result;
}
时间复杂度不用看代码,直接想做排列就是n!
#47
先是把#46的set里放value改成set里放index,这里注意一点是,#46有两种实现方法,我的是放到set里,随想录是弄一个bool表。我这种放到set里面,必须要把原来放value改成放index,不然不行。但他那种弄bool表的,只需要把原来这一句不要再写就行
if (used[i] == true) continue; // path里已经收录的元素,直接跳过
然后准备去重,一时没想到去重逻辑,偷个懒,先用set of vec做一下,过了:
set> res;
vector vec;
void backtrack(vector& nums, set used){
if(vec.size()==nums.size()){
res.insert(vec);
return;
}
for(int i=0;i> permuteUnique(vector& nums) {
set used;
backtrack(nums,used);
vector> result(res.begin(),res.end());
return result;
}
好,现在来讲正经去重逻辑,本题是 40.组合总和II 去重逻辑 和 46.全排列 的结合
重中之重是这句:if (i > 0 && nums[i] == nums[i - 1] && used.find(i-1)!=used.end()) continue;
排序后,前后相等的元素,而且前一个用过了,就不会让再来一次了
举个例子:
idx [0, 1, 2 ] [1, 0, 2 ]
val [1, 1, 2 ] [1, 1, 2 ]
就这两个东西不应该都出现的,这句就能保证
vector> res;
vector vec;
void backtrack(vector& nums, set used){
if(vec.size()==nums.size()){
res.push_back(vec);
return;
}
for(int i=0;i 0 && nums[i] == nums[i - 1] && used.find(i-1)!=used.end()) continue;
vec.push_back(nums[i]);
used.insert(i);
backtrack(nums,used);
vec.pop_back();
used.erase(i);
}
}
vector> permuteUnique(vector& nums) {
sort(nums.begin(),nums.end());
set used;
backtrack(nums,used);
return res;
}