day-29 代码随想录算法训练营 回溯part5

491.递增子序列

分析:存在重复元素,求递增子序列思路:1.树层去重2.当 i>0 时当前位大于上一位 

 day-29 代码随想录算法训练营 回溯part5_第1张图片

 思路:

  • 去重逻辑在每一层都需要重新创建(每一层遍历),且不能影响到下一层递归
class Solution {
public:
    vector>res;
    vectormid;
    
    void backtrace(vector&nums,int startIndex){
        if(mid.size()>=2)
            res.push_back(mid);
        if(startIndex==nums.size())
            return;
        unordered_setupset;//只影响该树层
        for(int i=startIndex;inums[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> findSubsequences(vector& nums) {
        backtrace(nums,0);
        return res;
    }
};

46.全排列

思路一:直接在结果数组中查找是否出现过此下标
思路二:使用set进行下标去重
class Solution {
public:
    vector>res;
    vectormid;
    unordered_setindex;
    void backtrace(vector&nums,int start){
        if(start==nums.size()){
            res.push_back(mid);
            return;
        }

        for(int i=0;i> permute(vector& nums) {
        backtrace(nums,0);
        return res;
    }
};

47.全排列||

思路一:进行树枝的去重,树层的去重直接使用find函数
思路二:树层去重(需要排序)+树枝去重
分析:本质上还是树层去重,在上一题全排列的基础上,每一层的遍历中有重复元素

day-29 代码随想录算法训练营 回溯part5_第2张图片

class Solution {
public:
    vector>res;
    vectormid;
    unordered_setindex;//记录递归下标
    
    void backtrace(vector&nums,int start,vector&used){
        if(start==nums.size()){
            res.push_back(mid);
            return;
        }
        
        for(int i=0;i0 && 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> permuteUnique(vector& nums) {
        sort(nums.begin(),nums.end());//需要排序
        vectorused(nums.size(),false);//记录重复值的使用
        backtrace(nums,0,used);
        return res;
    }
};

 455.分发饼干

思路:先排序,按最大的胃口和最大的饼干数来分配,使用双指针倒序遍历计数
class Solution {
public:
    int findContentChildren(vector& g, vector& 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& nums) {
        //思路一:直接计算峰顶和峰底的个数
        if(nums.size()<=1) return nums.size();
        int curDiff=0;//当前数和后一个数的差值
        int preDiff=0;//前一个数和当前数的差值(初始化为0方便第一个元素计算)
        int sum=1;
        for(int i=0;i0) || (preDiff>=0 && curDiff<0)){
                sum++;
                preDiff=curDiff;//峰值出现后更新prediff
            }
        }
        return sum;
    }
};

你可能感兴趣的:(#,代码随想录算法训练营(19),算法,leetcode,数据结构)