491.递增子序列
终止条件同样是回溯的常用终止条件:当index超过数组大小时,结束。
同时每一次递归开始都要判断path大小是否大于1:
if(path.size()>=2){
result.push_back(path);
}
if(index>nums.size())return;
同时还要加入判别条件:即当前元素小于path中最后塞入的元素,以及同层元素不能再重复作为开头分割:例如4467 出现两个467的情况:
if((!path.empty()&&nums[i]<path.back())||uset.find(nums[i])!=uset.end()){
continue;
}
而每次递归都需要重新定义set,因为这只是当前层次递归内所需要的记录,下一层就不需要记住了。
unordered_set<int> uset;
46.全排列
这是自己想出来的:
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
void backtracking(vector<int>& nums,int size){
if(path.size()==size){
result.push_back(path);
}
for(int i=0;i<nums.size();i++){
path.push_back(nums[i]);
vector<int>temp;
for(int j=0;j<nums.size();j++){
if(nums[j]!=nums[i]){
temp.push_back(nums[j]);
}
}
backtracking(temp,size);
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
result.clear();
path.clear();
int size=nums.size();
backtracking(nums,size);
return result;
}
};
每次通过改变numsde大小,防止当前枝前面出现的元素重复出现,但是比起定义used表虽然好理解,却相对麻烦,难以扩展。
47.全排列 II
排列的问题,因为是要求所有元素都存在,故应该每次递归时path的大小一旦等于nums就可以塞入result。同时每一层i的起始位置都要从0开始循环,从新挨个查找:
if(path.size()==nums.size()){
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++){
此外就是含有重复元素的降重,本来组合问题每次循环从0开始就要就要把本枝用过的元素标记住,同时若是nums中含有重复的元素就要把相邻的重复元素(排好队后)略过一个,这是对于同一层的操作:
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是对于同一层的操作,第二个if是对于同一枝的后续操作。
同时不要忘记排队,不然会重复输出:
sort(nums.begin(),nums.end());//忘记排队,输出重复。