【算法训练 day34 分发饼干、摆动序列、最大子数组和】


一、分发饼干-LeetCode 455

Leecode链接: leetcode 455
文章链接: 代码随想录
视频链接: B站

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1

思路

贪心算法策略是每一步都考虑最好的选择,以此来达到整体最好的选择。个人这里从饼干开始遍历,首先对连个数组进行排序,优先使用小饼干满足胃口小的孩子,判断该饼干是否满足孩子胃口,如果满足就遍历下一个饼干与下一个孩子,否则只遍历下一个饼干。

实现代码

1.双循环

//cpp
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int index = 0;
        int sum = 0;
        for(int i = 0;i<g.size();i++){
            for(int j = index;j<s.size();j++){
                if(s[j] >= g[i]){
                    sum++;
                    index = j + 1;
                    break;
                }
            }
        }

        return sum;
    }
};

2.单循环

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

个人问题

这里我自己使用了两个循环,其实没必要,因为最外层循环是对孩子进行遍历,只有饼干满足了孩子胃口指向孩子的指针才会递增,不如直接一层循环,只有饼干满足第一个孩子胃口时,指向孩子的指针才递增。

总结

整体比较简单,但有更好的解决办法。


二、摆动序列-LeetCode 376

Leecode链接: LeetCode 376
文章链接: 代码随想录
视频链接: B站

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。

示例:

输入:nums = [1,7,4,9,2,5]
输出:6
解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3)

思路

判断是否是摆动的,主要判断一个点两端是否交替出现递增递减的区域。

实现代码

//cpp
class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        int cur = 0;
        int pre = 0;
        int count = 1;
        for(int i = 0;i<nums.size();i++){
        	cur = nums[i+1] - nums[i];
        	if(pre <= 0&&cur>0 || pre >= 0&&cur<0){
        		count++;
        		pre = cur;
        	}
        }
        return count;
    }
};

个人问题

没有实现代码。

总结

题目有许多细节需要进行判断,首先是普通情况,一个点的左右都是严格单调递增与递减出现,此时直接count自增,并将当前的差值cur赋值给pre,为后续判断做准备。特殊情况,单调递增与单调递减之间出现了连续相等的值,这时需要将这些值相等情况忽略掉,忽略的方法就是在判断时添加=。例如:某个点与后一个点的差值为负值时,前一个点与当前点差值为零时,我们认为这是摆动的,例如[2,1,1,2]。最后一种情况,在单调递增或者单调递减中出现值相等,比如[2,3,3,3,4],这时摆动序列长度一眼就是2,这种情况需要我们将pre = cur这句话放在if里面,表示只有出现局部区域最大值或最小值时,pre才会更新。因为考虑到第一个元素肯定是摆动的,所以count初始值就是1。


三.最大子数组和-LeeCode 53

Leecode链接: LeetCode 53
文章链接: 代码随想录
视频链接: B站

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6

思路

使用一个中间变量sum保存遍历数组过程中的和,maxnum保存sum中出现过的最大值。如果遍历时sum出现了负值,就把sum赋值为0,表示取消前面所有的子集,重新开始计算和,保证取到值是最大的。

实现代码

//cpp
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
    	int sum = 0;
	    int maxnum = INT32_MIN;
	    for (int i = 0; i < nums.size(); i++) {
		    sum = sum + nums[i];
		    if (sum > maxnum) {
			    maxnum = sum;
		    }
		    if (sum < 0) {
			    sum = 0;
		    }
		}
	    return maxnum;
    }
};

个人问题

在判断是否更新maxnum时,写成了if(sum>0) maxnum = sum。如果数组的正数比较多没问题,但测试案例中有很多的负值,最后最大的值应该是个负值才对,就导致答案不对。

总结

本体的贪心策略在于,每次选数据时判断选之后的和是否大于上次保存的最大值,如果大于就更新,否则就继续遍历数组。并且如果和小于零就把和重置为0,这样操作保证了如果出现负值,就表示将之前所有遍历的和都取消,因为负值肯定是不需要的,如果要了负值的结果肯定比不要的差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值