class Solution {
private:
vector<vector<int>>result;
vector<int>path;
void bt(vector<int>& nums, int l){
if(l==nums.size()) return;
unordered_set<int>used;
for(int i=l;i<nums.size();i++){
if(used.find(nums[i])!=used.end()) continue;
path.push_back(nums[i]);
used.insert(nums[i]);
if(path.size()>1){
if(path[path.size()-1]<path[path.size()-2]){
path.pop_back();
continue;
}
result.push_back(path);
}
bt(nums,i+1);
path.pop_back();
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
bt(nums,0);
return result;
}
};
这题笔者对回溯的处理稍有不同,并不是将path加入result与退出一层回溯绑定,这样就不需要再回溯中加一个参数记录还需要回溯几层,而是将同起点元素的全部答案全部找出后,更换起点。这题与此前的求组合也不同,在于这题要得到子序列,所以不能通过排序的手段去重,所以就再每层回溯中增加一个哈希表,记录曾经作为过起点的元素,再之后的循环中遇到哈希表中存在的匀速就跳过本轮循环,直接进入下一轮。可以这样去重的原理在于,访问到的哈希表中不存在的元素,是相同元素中索引最小的,意味着这一元素再次出现时,剩余序列是第一次出现时剩余序列的子序列,所以在第一次出现时,就可以将该元素作为起始的所有递增序列全部求出来。
class Solution {
private:
vector<vector<int>>result;
vector<int>path;
void bt(vector<int>& nums){
if(nums.size()==0){
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++){
path.push_back(nums[i]);
nums.erase(nums.begin()+i);
bt(nums);
nums.insert(nums.begin()+i,path[path.size()-1]);
path.pop_back();
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
bt(nums);
return result;
}
};
构造循环,逐个取出元素加入path,并从nums中删除后,进入下一层回溯,下一层回溯退出后,将元素插回nums原位置,并从path中删除,是否将path加入result的判断标准是nums是否为空。
class Solution {
private:
vector<vector<int>>result;
vector<int>path;
void bt(vector<int>& nums){
if(nums.size()==0){
result.push_back(path);
return;
}
int pre=11;
for(int i=0;i<nums.size();i++){
if(nums[i]==pre) continue;
else pre=nums[i];
cout<<i;
path.push_back(nums[i]);
nums.erase(nums.begin()+i);
bt(nums);
nums.insert(nums.begin()+i,path[path.size()-1]);
path.pop_back();
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());
bt(nums);
return result;
}
};
这题就是传统艺能,通过对nums排序,在每层回溯中只将第一次出现的元素作为可以加入path的元素,对结果进行去重。