代码随想录第31天

文章介绍了两种算法问题的解决方案。一是分发饼干的问题,通过排序和双指针策略确保大饼干优先分配给大胃口的孩子。二是摆动序列的判断,利用贪心算法跟踪序列中的转折点,避免在单调坡中记录平坡。同时,文章还讨论了最大子数组问题,提供了暴力解法和贪心算法的实现,强调在连续和为正时才可能增加总和。
摘要由CSDN通过智能技术生成

1.分发饼干:

大饼干先喂大胃口,for循环遍历胃口

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int index = s.size() - 1; // 饼干数组的下标
        int result = 0;
        for (int i = g.size() - 1; i >= 0; i--) { // 遍历胃口 
            if (index >= 0 && s[index] >= g[i]) { // 遍历饼干 
                result++;
                index--;
            }
        }
        return result;
    }
};

注:

1.

这里用一个for好一点,用两个for的话有点麻烦,他那个”吃“过的不用再遍历了。 

2.

注意版本一的代码中,可以看出来,是先遍历的胃口,在遍历的饼干,那么可不可以 先遍历 饼干,在遍历胃口呢?

其实是不可以的。

外面的for 是里的下标i 是固定移动的,而if里面的下标 index 是符合条件才移动的。

如果 for 控制的是饼干, if 控制胃口,就是出现如下情况 :

if 里的 index 指向 胃口 10, for里的i指向饼干9,因为 饼干9 满足不了 胃口10,所以 i 持续向前移动,而index 走不到s[index] >= g[i] 的逻辑,所以index不会移动,那么当i 持续向前移动,最后所有的饼干都匹配不上。

所以 一定要for 控制 胃口,里面的if控制饼干。

小饼干先喂小胃口,for循环遍历饼干:

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int index = 0;
        for(int i = 0; i < s.size(); i++) { // 饼干
            if(index < g.size() && g[index] <= s[i]){ // 胃口
                index++;
            }
        }
        return index;
    }
};

这里也不能反过来(接下来是反过来的代码):

 

 index动不了for循环j一直往下,最后一个都输出不了

2.摆动序列:

自己写对于如何获得子序列完全不知道,因为他可以删除元素这个不好弄。而且一开始根本没想到和贪心算法有什么关系。

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.size() <= 1) return nums.size();
        int curDiff = 0; // 当前一对差值
        int preDiff = 0; // 前一对差值
        int result = 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)) {
                result++;
                preDiff = curDiff; // 注意这里,只在摆动变化的时候更新prediff 
            }
        }
        return result;
    }
};

1.他不用删除元素他是记录转折点:

 

 2.关于平坡:
对于上下坡中的平坡,记录最右边那个:

对于单调坡中的平坡:

 

 本来的代码是:

 for (int i = 0; i < nums.size() - 1; i++) {
            curDiff = nums[i + 1] - nums[i];
            // 出现峰值
            if ((preDiff <= 0 && curDiff > 0) || (preDiff >= 0 && curDiff < 0)) {
                result++;
            }
            preDiff = curDiff;
        }

preDiff随着i的移动更新,但是发现这样在单调坡中有平坡会被记录 ,比如上面那种情况答案是2但是代码给出的是3,所以要改成有摆动的更新preDiff,这样在单调坡中有平坡就不会被记录了。

3.关于始末点:

只有一个值或者两个一样的值时输出1,两个不一样的值输出2,在代码中他是假设初始点前面还有一个和初始点一样的值,这样最开始的preDiff=0,默认result=1(默认最后一个值是一个峰),当只有两个不一样的值的时候,只会遍历到第一个,第一个是左平右不平,result++,输出2,当两个一样的值的时候,只会遍历到第一个,左平右也平,result不++,最后只会输出1.其实默认始末点是两个峰值,(两个值不一样),但是不能让result的初始值为2,因为万一真只有两个一样的值不就错了吗。

3.最大字数数组:

暴力解法(淦,连暴力解法都没想到):

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;
    }
};

 贪心算法:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int result = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); i++) {
            count += nums[i];
            if (count > result) { // 取区间累计的最大值(相当于不断确定最大子序终止位置)
                result = count;
            }
            if (count <= 0) count = 0; // 相当于重置最大子序起始位置,因为遇到负数一定是拉低总和
        }
        return result;
    }
};

 局部最优:求局部最大的连续和,当出现连续和小于0时重新开始计算连续和,这里为什么不是当num[i]小于0时重新计算连续和,因为只要连续和不是小于0,那后面有可能有正的加上就会使连续和变的更大,还是举个例子更好:

nums = [-2,1,-3,4,-1,2,1,-7,4]
count1=1,count2=6,count=4.

就像在计算第2个count时,从4到1中间遇到-1但是还是没有重新算,因为4-1不会使连续和小于0,这样对于后面的数来说正的对后面的元素 起到增大总和的作用。 所以只要连续和为正数我们就保留。

这里也会有录友疑惑,那 4 + -1 之后 不就变小了吗? 会不会错过 4 成为最大连续和的可能性?

其实并不会,因为还有一个变量result 一直在更新 最大的连续和,只要有更大的连续和出现,result就更新了,那么result已经把4更新了,后面 连续和变成3,也不会对最后结果有影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值