491.递增子序列
分析:存在重复元素,求递增子序列思路:1.树层去重2.当 i>0 时当前位大于上一位
思路:
- 去重逻辑在每一层都需要重新创建(每一层遍历),且不能影响到下一层递归
class Solution {
public:
vector<vector<int>>res;
vector<int>mid;
void backtrace(vector<int>&nums,int startIndex){
if(mid.size()>=2)
res.push_back(mid);
if(startIndex==nums.size())
return;
unordered_set<int>upset;//只影响该树层
for(int i=startIndex;i<nums.size();i++){
if(!mid.empty() && mid.back()>nums[i])//递增序列条件
continue;
if(upset.find(nums[i])!=upset.end())//该树层存在重复值,并且不是第一次遍历
continue;
upset.insert(nums[i]);//记录第一次遍历
mid.push_back(nums[i]);
backtrace(nums,i+1);
mid.pop_back();
}
}
vector<vector<int>> findSubsequences(vector<int>& nums) {
backtrace(nums,0);
return res;
}
};
46.全排列
思路一:直接在结果数组中查找是否出现过此下标
思路二:使用set进行下标去重
class Solution {
public:
vector<vector<int>>res;
vector<int>mid;
unordered_set<int>index;
void backtrace(vector<int>&nums,int start){
if(start==nums.size()){
res.push_back(mid);
return;
}
for(int i=0;i<nums.size();i++){
if(index.find(i)!=index.end())//在树枝中进行下标去重
continue;
index.insert(i);
mid.push_back(nums[i]);
backtrace(nums,start+1);
mid.pop_back();
index.erase(i);
}
}
//树枝去重
vector<vector<int>> permute(vector<int>& nums) {
backtrace(nums,0);
return res;
}
};
47.全排列||
思路一:进行树枝的去重,树层的去重直接使用find函数
思路二:树层去重(需要排序)+树枝去重
分析:本质上还是树层去重,在上一题全排列的基础上,每一层的遍历中有重复元素
class Solution {
public:
vector<vector<int>>res;
vector<int>mid;
unordered_set<int>index;//记录递归下标
void backtrace(vector<int>&nums,int start,vector<bool>&used){
if(start==nums.size()){
res.push_back(mid);
return;
}
for(int i=0;i<nums.size();i++){
if(i>0 && nums[i]==nums[i-1] && !used[i-1])//树层重复元素去重(used避免的树枝的去重,因为存在重复元素)
continue;
if(index.find(i)!=index.end())//树枝下标元素去重
continue;
index.insert(i);//树枝递归记录下标
used[i]=true;//树枝递归记录使用
mid.push_back(nums[i]);
backtrace(nums,start+1,used);
mid.pop_back();
index.erase(i);
used[i]=false;
}
}
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(),nums.end());//需要排序
vector<bool>used(nums.size(),false);//记录重复值的使用
backtrace(nums,0,used);
return res;
}
};
455.分发饼干
思路:先排序,按最大的胃口和最大的饼干数来分配,使用双指针倒序遍历计数
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
sort(g.begin(),g.end());
sort(s.begin(),s.end());
int i=g.size()-1,j=s.size()-1;
int sum=0,maxsum=0;
while(i>=0 && j>=0){
if(s[j]>=g[i]){
j--;
i--;
sum++;
}
else
i--;
maxsum=max(maxsum,sum);
}
return maxsum;
}
};
376.摆动序列
分析:考虑三种情况
- 存在单调增和单调减
- 存在平区间
- 在单调增或单调减中存在平区间
思路:遍历序列,采用三个变量,前数与当前数之差prediff,当前数与下一个数之差curdiff,摆动序列总长度sum。
当出现摆动时,即出现峰值:
-
单调区间直接判断prediff和curdiff一正一反;
-
平区间则判断prediff==0的情况下,若curdiff不为0则有摆动
-
出现峰值才更新preidff,不然在单调区间内存在平区间,就会导致每个平区间多一个记录
class Solution {
public:
int wiggleMaxLength(vector<int>& nums) {
//思路一:直接计算峰顶和峰底的个数
if(nums.size()<=1) return nums.size();
int curDiff=0;//当前数和后一个数的差值
int preDiff=0;//前一个数和当前数的差值(初始化为0方便第一个元素计算)
int sum=1;
for(int i=0;i<nums.size()-1;i++){
curDiff=nums[i+1]-nums[i];
//出现峰值的情况
if((preDiff<=0 && curDiff>0) || (preDiff>=0 && curDiff<0)){
sum++;
preDiff=curDiff;//峰值出现后更新prediff
}
}
return sum;
}
};