提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、递增子序列
- 二、全排列
- 三、全排列2
前言
今天是跟着代码随想录刷题的第29天,今天主要学了以下几个内容:491.递增子序列、46.全排列、46.全排列
链接地址:递增子序列、全排列、全排列2
一、递增子序列
思路:这道题需要注意的点就是在收取结果的时候要判断数组长度大于2,还有一个就是如何去重,他这里需要用到set,如果这个元素在set里面有相应的元素,就不能放进去,因为是横向去重,所以在也就是说进入新一层递归的话,这个set需要被重置的,这样的话,他就不能做回溯的操作了,只需要在函数的内部定义这个set就可以了,这样进入新一轮递归的话,就刷新了set,还有一个就是需要递增的逻辑的就是,你拿过来的元素一定要比path的最后一个元素小的话,也需要跳过。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
void backtracking(vector<int>& nums,int start)
{
if(path.size()>1) result.push_back(path);
if(start>=nums.size()) return;
unordered_set<int> result_set;
for(int i=start;i<nums.size();i++)
{
if(i>0)
{
if(result_set.find(nums[i])!=result_set.end()) continue;
if(path.size()>0&&nums[i]<path.back()) continue;
}
result_set.insert(nums[i]);
path.push_back(nums[i]);
backtracking(nums,i+1);
path.pop_back();
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
result.clear();
path.clear();
backtracking(nums,0);
return result;
}
};
版本2:
这里是用数组来去重,因为数字从-100到100,所以需要两百数组,又因为数组不能负下标,所以所以全部加100,用过了,那里的下标就标成1,检查如果是1,就不能用,如果进入下一层递归,又是一个新数组。就没问题。
这里需要注意一下和之前全局数组的区别,之前是我这一层是变为1,又回来,所以上一个如果是0,就能知道是重复,最重要的是我可以对比这一个和上一个是不是相等,因为如果没有这个值,他也是0,我如何区分有没有这个值呢,因为排序过了,通过对比这个和上个是不是相等,如果相等,又是0,就说明很有问题,但是这道题不能这样,因为我没有排序,如果有一样的元素,我不知道在哪,就算是0,也可能是她本来就没有这个元素,不能代表是同一层
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
if (path.size() > 1) {
result.push_back(path);
}
int used[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]
for (int i = startIndex; i < nums.size(); i++) {
if ((!path.empty() && nums[i] < path.back())
|| used[nums[i] + 100] == 1) {
continue;
}
used[nums[i] + 100] = 1; // 记录这个元素在本层用过了,本层后面不能再用了
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> findSubsequences(vector<int>& nums) {
result.clear();
path.clear();
backtracking(nums, 0);
return result;
}
};
二、全排列
思路:这里没有start,就是需要used去重罢了。
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
int used[21]={0};
void backtracking(vector<int>& nums)
{
if(path.size()==nums.size())
{
result.push_back(path);
return;
}
for(int i=0;i<nums.size();i++)
{
if(used[nums[i]+10]==1) continue;
path.push_back(nums[i]);
used[nums[i]+10]=1;
backtracking(nums);
used[nums[i]+10]=0;
path.pop_back();
}
}
vector<vector<int>> permute(vector<int>& nums) {
result.clear();
path.clear();
backtracking(nums);
return result;
}
};
还有一种用bool下标数组来写的
三、全排列2
思路:总结一下方法:下标一一对应来标记去重缺点是只可以做那些允许你给原数组排序的题,这样才能把一样的数放到一起,优点是可以做树枝去重(就是没有startindex需要去重自己元素);元素去重限制比较多,只能做简单的树层去重,这道题涉及到了树枝去重做不了了。
这里就用的下标数组来做,注意就是既要进行树枝去重又要进行树层去重。
代码:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
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++)
{
if(used[i]==true) continue;
if(i>0&&nums[i]==nums[i-1]&&used[i-1]==0) continue;
used[i]=true;
path.push_back(nums[i]);
backtracking(nums,used);
used[i]=false;
path.pop_back();
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
result.clear();
path.clear();
vector<bool> used(nums.size(),false);
sort(nums.begin(),nums.end());
backtracking(nums,used);
return result;
}
};