贪心算法&376摆动序列&53最大子序和&455分发饼干

 

day31


贪心算法

image-20230312161516223


455.分发饼干

题目链接:455. 分发饼干

解题思路:参考 视频

局部最优,保证大饼干能够满足大孩子,依次遍历,外层一定是孩子的胃口。

// 时间:O(nlogn)
// 空间:O(1)
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        // 小孩和饼干从小到大排序
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());

        int result = 0;	//这里一定要给result赋初值
        int index = s.size()-1;

        //开始小孩从大到小遍历,取局部最优
        for( int i = g.size() - 1 ; i >= 0 ; i--){
            if ( index >= 0 && s[index] >= g[i]){
                result++;
                index--;
            }
        }
        return result;
    }
};

376.摆动序列

题目链接:376. 摆动序列

解题思路:参考 视频

  • 贪心解法

376.摆动序列

根据局部最优(删除单调坡度上的节点(不包括单调坡度两端的节点))推导全局最优(整个序列最多的局部峰值)

实际操作上,其实连删除的操作都不用做,因为题目要求的是最长摆动子序列的长度,所以只需要统计数组的峰值数量就可以了(相当于是删除单一坡度上的节点,然后统计长度)

定义两个变量,prediff(nums[i]-nums[i-1])curdiff(nums[i+1] - nums[i])

// 有波动的情况
prediff < 0 && curdiff > 0 或者 prediff > 0 && curdiff < 0

根据分析,本题有三种情况

  1. 上下坡中有平坡

img

如上图,摆动序列的长度是3,因此需要删除掉前三个2,判断条件就是根据之前的两个变量。

img

对于第一个2和最后一个2,有不同的方式,统一规则删除前面的三个,这个时候判断条件就有加prediff==0的情况。

  1. 数组首尾两端

相当于前面加了一个元素,还是满足等于0的情况。

376.摆动序列1

  1. 单调坡中有平坡

img

这种情况在于更新prediff的规则,只有当计算出来坡度摆动的时候再更新prediff,这样就能得到最后的结果。

本题注意两种平坡的情况:上下中间有平坡,单调有平坡

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        // 判断等于1的情况
        if( nums.size() <= 1) return nums.size();
        int result = 1;     //初始记录最后一个元素坡度
        int prediff = 0;    //相当于首位元素有坡度
        int curdiff = 0;    
        for( int i = 0; i < nums.size() - 1; i++){  //这里不包括最后一个元素,因为result已经记录了其坡度
            curdiff = nums[i+1] - nums[i];  //给curdiff赋值,prediff的赋值后面更新
            if( (prediff >= 0 && curdiff < 0) || (prediff <= 0 && curdiff >0)){ // 统一更新规则
                result++;
                prediff = curdiff;
            }
            
        }
        return result;


    }
};

53.最大子序和

题目链接:53. 最大子数组和

题目思路:参考 视频

暴力解法

// 时间复杂度:O(n^2)
// 空间复杂度:O(n)
// 暴力超时
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); i++) { // 设置起始位置
            count = 0;
            for (int j = i; j < nums.size(); j++) { // 每次从起始位置i开始遍历寻找最大值
                count += nums[j];
                result = count > result ? count : result;
            }
        }
        return result;
    }
};

贪心解法

局部最优的思路:当连续和为负数的时候立刻放弃前面所有值,直接置为0,从下一个元素重新计算连续和,因为负数加上下一个元素指挥变小

全局最优:选取最大的连续和

局部最优的情况下,并记录最大的“连续和”,可以推出全局最优

53.最大子序和

关于如何收获最大值,当计数值大于结果值就更新结果值。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int sum = 0;    //计算中间值
        int result = INT_MIN;
        for( int i = 0; i < nums.size(); i++){	//遍历数组
            sum += nums[i];			// 累加数组
            // result = max( sum, result);
            if( sum > result ) result = sum;
            if( sum < 0 ){	//当发现总和为负直接变为0
                sum = 0;
            }
            
        }
        return result;
    }
};