[学习报告]《LeetCode零基础指南》(第七讲) 贪心---gyro v1.0

0. 知识概念

  1. 贪心算法:不断转化问题,寻求问题的局部最优解。并不能保证数学上的整体绝对最优,而是保证工程上的整体最优。
  2. 步步贪心
    先特殊,后一般;首先要先考虑特殊情况
    第一步

(1) 明确到底什么是最优解?

————即用 数学化&定量化所解问题的目的值&要求,约束值&要求,逻辑化&结构化的策略重新描述问题,
让问题进一步的清晰和具体。

1)数学化&定量化:转述问题,强调问题中的目的:结果数值。约束:条件数值
分析问题 目的值:求哪个数值—结果数值 目的要求:max,min等
约束值:限制条件—条件数值 约束要求:<,>=,>,<==等
e.g. 背包问题的重量有限,价值最大?
————目的值&要求:价值&最大
————约束值&要求:重量&小于
e.g. 救生艇问题?
————目的值&要求:船数量&最少
————约束值&要求:(1)人数&小于2(2)人重量&小于船载荷
e.g. 三角形最大周长问题?
————目的值&要求:周长&最大
————约束值&要求:任意两边之和&小于第三边
e.g. 1913. 两个数对之间的最大乘积差
————目的值&要求值:数对乘积差&最大
————约束值&要求值:4个数配对&任意

2)逻辑化&结构化:指所求问题,要求按一定的逻辑排序之类的。需要明确其逻辑和结构。
理解问题,抓住关键将问题的表述用结构化的数据来表述。

第二步

明确什么是子问题的最优解?
–施加影响,改变结构

第三步

分别求出子问题的最优解再堆叠出全局最优解?

分别求出子问题的最优解再堆叠出全局最优解?

1. 解题报告

题目见:《LeetCode零基础指南》(第七讲) 贪心

Q1. 1913. 两个数对之间的最大乘积差

/*第一步: 明确到底什么是最优解?
	答:最大的两个数乘积与最小的两个数的乘积
	
  第二步: 明确什么是子问题的最优解?
  答:<--找到最大的两个数;找到最小的两个数<--排序
	
第三步	分别求出子问题的最优解再堆叠出全局最优解?
答:最大的两个数相乘后-最小的两个数相乘
	
	*/
/*先排序*/
int cmp(const void *a,const void *b)
{
    return *(int *)a - *( int *)b;/*递增*/
}

int maxProductDifference(int* nums, int numsSize){
/*s1:排序*/
    qsort(nums,numsSize,sizeof(int),cmp);

    return nums[numsSize-1]*nums[numsSize-2]-nums[0]*nums[1];

}

Q2. 976. 三角形的最大周长

/*第一步: 明确到底什么是最优解?
	答:找到最长的三边,且符合条件(任意两边之和大于第三边)
	
  第二步: 明确什么是子问题的最优解?
  答:<--找到当前有效最长的三边<--排序
	
第三步	分别求出子问题的最优解再堆叠出全局最优解?
答:判断当前所找到的最长的三边是否可以组成三角形
	
	*/
int cmp(const void *a,const void *b)
{
    /*递减*/
    return *(int *)b-*(int *)a;/*debug:int 与*写反*/
}

int largestPerimeter(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);

    int i;
    /*排序后*/
    for(i=0;i<numsSize-2;++i)
    {
        if(nums[i+1]+nums[i+2]>nums[i])
        return nums[i+1]+nums[i+2]+nums[i];
    }

    return 0;

}

Q3. 561. 数组拆分 I


  /*第一步: 明确到底什么是最优解?
	答:每一组数对中的较小值尽可能的大
	
    第二步: 明确什么是子问题的最优解?
    答:<--每一个当前的最大值与当前的次最大值组合<--排序
	
    第三步	分别求出子问题的最优解再堆叠出全局最优解?
    答:排序后,较小值间隔分布,遍历求和
	
	*/
    int cmp(const void *a,const void *b)
    {
        return *(int *)a-*(int *)b;
    }
    
    int arrayPairSum(int* nums, int numsSize){

        qsort(nums,numsSize,sizeof(int),cmp);

        int i;
        int sum = 0;
        for(i = 0;i < numsSize;i = i+2)
        {
            sum +=*(nums+i);/*debug:漏写+i*/
        }
        return sum;
  

}

Q4. 881. 救生艇


  /*第一步: 明确到底什么是最优解?
	答:把在limit限度内,将人分成2个或1个一组,使得组数最少
	
    第二步: 明确什么是子问题的最优解?
    答:<--尽可能地分成2人一组
 
	
    第三步	分别求出子问题的最优解再堆叠出全局最优解?
    答:如何实现:<--排序后,找出更high的人较low的人一组,看是否小于limit;;
    
    	
       若和小于limit,去掉该两人,缩小样本;
       若和大于limit,去掉较重者,缩小样本
	
	*/

int cmp(const void *a,const void *b)
{
    /*递减*/
    return *(int *)b-*(int *)a;
}

int numRescueBoats(int* people, int peopleSize, int limit){
    /*递减排序*/
    qsort(people,peopleSize,sizeof(int),cmp);

    int cnt_ship=0;
    int l=0,r=peopleSize-1;
    /*(1)按重量从大到小排列
(2)如果只剩一个即:l = r,船cnt_ship++,break;退出循环
(3)如果首尾相加大于limit,则cnt_ship++,l++;
(4)如果首尾相加小于或等于limit,则cnt_ship++,l++,r--;

*/
/*总人数为偶数时,究极情景:l<r ,直接跳出循环,控制左右不会出现交错的情况*/
    while( l <= r )
    {
        if( l == r)/*总人数为奇数时,究极情景,l == r,跳出循环*/
        {
            cnt_ship++;
            break;
        }
        else if(people[l]+people[r]>limit)
        {
            cnt_ship++;l++;
        }
        else 
        {
            cnt_ship++;l++;r--;
        }
    }

    return cnt_ship;

}

Q5:324. 摆动排序 II

/*Alpha 0.0,题目考虑不周全,没考虑到数值有连续重复超过3次以上的项,仅仅在连续项不超过3项的时候成立*/
int cmp(const void *a,const void *b)
{
    return *(int *)a-*(int *)b;/*递增*/
}

void wiggleSort(int* nums, int numsSize){

    qsort(nums,numsSize,sizeof(int),cmp);
    /*再申请1个数组*/
    int *ans = (int *)malloc(sizeof(int)*numsSize); 
    int i;
    for(i=0;i<numsSize;++i)
    {
        *(ans+i) = *(nums+i);
    }
    /*第0项是最小值,拍最前面,直接安排*/
    *(ans) = *(nums);
    /*消除不确定性,numsSize值为奇或偶,分类讨论*/
    if(numsSize%2)  /*numsSize值为奇数*/
    {
        for(i=1;i<numsSize-1;i=i+2)
        {
            nums[i]=ans[i+1];
            nums[i+1] = ans[i];
        }
    }
    else/*numsSize值为偶数*/
    {
        for(i=1;i<numsSize-2;i=i+2)
        {
            nums[i]=ans[i+1];
            nums[i+1] = ans[i];
        }
        nums[numsSize-1]=ans[numsSize-1];/*最后一项,单独考虑*/
    }

    free(ans);

}
/*Beta 0.0*/
int cmp(const void *a,const void *b)
{
    return *(int *)a-*(int *)b;/*递增*/
}

void wiggleSort(int* nums, int numsSize){

    qsort(nums,numsSize,sizeof(int),cmp);
    /*再申请1个数组*/
    int *ans = (int *)malloc(sizeof(int)*numsSize); 
    int i,r;
    for(i=0;i<numsSize;++i)
    {
        *(ans+i) = *(nums+i);
    }
  r = numsSize - 1;
    /*从前往后摆放,先从高到低,在偶数位摆最大的一部分,再接着从高到低摆奇数位,尽可能避免重复位*/
    /*将较大的一半填充到偶数位*/
    for(i=1;i<numsSize;i+=2)
    {
        *(nums+i)= *(ans + r--);
    }
/*将较小的一半填充到奇数位*/
    for(i=0;i<numsSize;i+=2)
    {
        *(nums +i) = *(ans + r--);
    }

    free(ans);

}

Q6:

/*method1:以孩子为中心*/
int cmp(const void *a, const void *b)
{
    return *(int *)a-*(int *)b;/*递增*/
}

int findContentChildren(int* g, int gSize, int* s, int sSize){
    qsort(g,gSize,sizeof(int),cmp);
    qsort(s,sSize,sizeof(int),cmp);

    int i,j=0,cnt=0;
    for(i=0;i<gSize;++i)
    {
        for(;j<sSize;)
        {
            if(s[j]>=g[i])
            {
                cnt++;
                j++;
                break;
            }
            else
            {
                j++;
            }
        }
        if(j==sSize)
        {
            break;
        }
    }
    

 return cnt;
}
/*以饼干为中心,使用while循环*/
int cmp(const void *a, const void *b)
{
    return *(int *)a-*(int *)b;/*递增*/
}

int findContentChildren(int* g, int gSize, int* s, int sSize){
    qsort(g,gSize,sizeof(int),cmp);
    qsort(s,sSize,sizeof(int),cmp);

    int i=gSize-1,j=sSize-1,cnt=0;
    while(i>=0&&j>=0)
    {
        /*以饼干为中心,饼干不够大,就换个胃口小点的孩子*/
        if(s[j]>=g[i])
        {
            j--;
            i--;
            cnt++;
        }
        else{
            i--;
        }
    }
    

 return cnt;
}

Q7:1827. 最少操作使数组递增

在这里插入代码片

思考总结(think&summary):

(1)程序书写时,眼睛盯着屏幕,专注,小心,不要出现错,漏,反等;(2)贪心算法,就是转化问题,将复杂的问题分解转化为可以具体的,简单的问题,步步贪心。
(3)工程上最优接近而不等于数学上最优。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值