代码随想录算法训练营第三十一天|455.分发饼干、376. 摆动序列、53. 最大子序和

目录

455. 分发饼干

376. 摆动序列

53. 最大子数组和

1. 分治法

2. 动态规划

3.贪心


455. 分发饼干

题目描述:

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

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

 一个人居然能有那么多孩子?!注定要饿死。

我的想法:对两个数组进行排序使用双指针,最优匹配,优先满足胃口最小的孩子,ret计数最多能满足多少孩子。

int cmp_int(const void* e1,const void* e2){
    return *(int*)e1-*(int*)e2;
}
int findContentChildren(int* g, int gSize, int* s, int sSize){
    //排序
    qsort(g,gSize,sizeof(int),cmp_int);
    qsort(s,sSize,sizeof(int),cmp_int);
    int ret=0;
    int left=0,right=0;
    while(right<sSize&&left<gSize){
        if(g[left]<=s[right]){
            ret++;left++;
        }
        right++;
    }
    return ret;
}

376. 摆动序列

题目描述:

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

    例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
    相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。

给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。

对于这个题目!首先,我得看得懂题!

有好多点需要注意:

  1. nums只有两个元素时,要判断两元素是否相同:相同是平的,摆动序列是1;相反,两元素不相同的情况下,摆动序列是2。
  2. nums数组的大小大于2的情况下,max的初始值并不是1。就如上面一条,如果前两个元素相同,只有一个应该被包含在摆动序列中;而如果两个元素不相同,两个元素都应该包含在摆动序列中(第9行代码)
  3. 遇到当前元素与前一元素差值为0的情况,应该有continue的操作以避免对predif做更新。如果更predif做更新,predif必然等于0,后续sign的值就永远为0,因此必然要continue。(第14行代码)
  4. 在对sign做判断时,条件如果是sign<0会漏掉一个序列元素。(第17行代码)

        如果没有对curdif=0的情况continue,那么容易在后面sign做判断时使用条件sign<0,就会造成下面错误:

正确代码如下:

int wiggleMaxLength(int* nums, int numsSize){
    int max=0;
    if(numsSize==1)     return max=1;
    //predif表示前一个差值
    int predif=nums[1]-nums[0];
    if(numsSize==2){
        return max=(predif==0)?1:2;
    }
    max=(predif==0)?1:2;
    for(int i=1;i<numsSize;i++){
        //curdif表示当前差值
        int curdif=(nums[i]-nums[i-1]);
        //当前差值为0的话,continue而不进行predif的更新
        if(curdif==0)  continue;
        int sign=predif*curdif;
        //等于0的情况保证前面是平坡的正确性
        if(sign<=0){
            max++;
        }
        predif=curdif;
    }
    return max;
}

53. 最大子数组和

太经典的题目很多种解法。

1. 分治法

int CrossingSubArray(int* nums,int low,int mid,int high){
	int max_left=INT_MIN,max_right=INT_MIN;
    int sum=0;
    //计算包括中间左边的最大子数组和
    for(int i=mid;i>=low;i--){
        sum+=nums[i];
        max_left=fmax(sum,max_left);
    }
    sum=0;
    //计算包括中间右边的最大子数组和
    for(int i=mid+1;i<=high;i++){
        sum+=nums[i];
        max_right=fmax(sum,max_right);
    }
    //两数相加=跨越中间的最大子数组和
    return max_left+max_right;
}
int maxArray(int* nums, int low,int high){
	if(low==high)	return nums[low];
	int mid=(low+high)/2;
    //分(左闭右闭)
	int S1=maxArray(nums,low,mid);
	int S2=maxArray(nums,mid+1,high);
    //计算跨越中间的最大子数组和
	int S3=CrossingSubArray(nums,low,mid,high);
    //比较最大值
	int max=fmax(S1,S2);
	max=fmax(max,S3);
	return max; 
}
int maxSubArray(int* nums, int numsSize){
	int max=maxArray(nums,0,numsSize-1);
	return max; 
}

2. 动态规划

int maxSubArray(int* nums, int numsSize){
    int* dp=(int*)malloc(sizeof(int)*numsSize);
    dp[0]=nums[0];
    int max=dp[0];
    for(int i=1;i<numsSize;i++){
        dp[i]=fmax(dp[i-1]+nums[i],nums[i]);
        max=(dp[i]>max)?dp[i]:max;
    }
    return max;
}

3.贪心

 连续和小于0的情况下,子序列重新开始选取;

连续和大于0的情况下,将元素添加到子序列并更新连续和的大小。

int maxSubArray(int* nums, int numsSize){
    int ret=INT_MIN;
    int sum=0;
    for(int i=0;i<numsSize;i++){
        sum+=nums[i];
        if(sum>ret)     ret=sum;
        if(sum<0)       sum=0;
    }
    return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值