九日集训(第六天) 贪心

懈怠了,但周五满课,然后周六又有军事理论考试还有篮球比赛,只在昨天又复习了一遍贪心算法/(ㄒoㄒ)/~

简单理解

  • 对所给数组进行排序(升序或者降序),然后通过题目取得最大(最小)和次大(次小 的两个书相乘(相加)得到最优解。

题目

1.最大乘积差

两个数对 (a, b) 和 (c, d) 之间的 乘积差 定义为 (a * b) - (c * d) 。
给你一个整数数组 nums ,选出四个 不同的 下标 w、x、y 和 z ,使数对 (nums[w], nums[x]) 和 (nums[y], nums[z]) 之间的 乘积差 取到 最大值 。

实现代码:

int cmp(int *a, int *b){
    return *(int *)a - *(int *)b;
}
int maxProductDifference(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);
    return nums[numsSize-1]*nums[numsSize-2]-nums[0]*nums[1];
}
  • 这道题结合了排序和贪心的思想,通过qsort排序得到有序数组,再根据题目要求运用贪心的思想求出最大乘积差。

2.三角形的最大周长

题目描述:给定由一些正数(代表长度)组成的数组 nums ,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。如果不能形成任何面积不为零的三角形,返回 0。

实现代码:

int cmp(int*a,int*b){
    return *(int*)a-*(int*)b;
}
int largestPerimeter(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);
    for(int i=numsSize-1;i>1;--i){
        if(nums[i-2]+nums[i-1]>nums[i]){
            return nums[i-2]+nums[i-1]+nums[i];
        }
    }
    return 0;
}
  • 运用三角形两边之和大于第三边来判断三角形是否符合要求;

3.数组拆分

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。

实现代码:

int cmp(int*a,int*b){
    return *(int*)a-*(int*)b;
}
int arrayPairSum(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);
    int ans=0;
    for(int i = 0;i<numsSize;i+=2){
        ans+=nums[i];
    }
    return ans;
}
  • 注意,通过排序直接取奇数数列(数对中的min),即可得到最大总和;

4.救生艇

给定数组 people 。people[i]表示第 i 个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit。
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit。
返回 承载所有人所需的最小船数

实现代码:

int cmp(int*a,int*b){
    return *(int*)a-*(int*)b;
}
int numRescueBoats(int* people, int peopleSize, int limit){
    qsort(people,peopleSize,sizeof(int),cmp);
    int ans=0;
    int i,k=0;
    for(i=peopleSize-1;k<=i;){
        ans++;
        if(people[i]+people[k]<=limit){
            i--;
            k++;
        }
        else{
            --i;
        }
    }
    return ans;
}
  • 两个边界(k和i)随着判断结束移动;

5.摆动排序Ⅱ

给你一个整数数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。
你可以假设所有输入数组都可以得到满足题目要求的结果。

实现代码:

int cmp(int *a, int *b){
    return *(int *)a - *(int *)b;
}
void wiggleSort(int* nums, int numsSize){
    int *ret = (int*)malloc(sizeof(int)*numsSize);
    for(int i=0;i<numsSize;i++){
        ret[i]=nums[i];
    }
    qsort(ret,numsSize,sizeof(int),cmp);
    int returnSize=numsSize-1;
    for(int i=1;i<numsSize;i+=2){
        nums[i]=ret[returnSize--];
    }
    for(int i=0;i<numsSize;i+=2){
        nums[i]=ret[returnSize--];
    }

    return nums;
}
  • 实现摆动的方法是先创建一个数组,并对其排序,然后根据题目先把大的数插入偶数列,再依次插入奇数列

6.分发饼干

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

实现代码:

int cmp(int*a,int*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 j=sSize-1,ans=0;
    for(int i=gSize-1;i>=0&&j>=0;i--){      // i>=0&&j>=0,不要忘记=
        if(g[i]>s[j]){
            continue;
        }
        else{
            j--;
            ans++;
        }
    }
    return ans;
}
  • 注意不要越界

7.最小操作使数组递增

给你一个整数数组 nums (下标从 0 开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。
比方说,如果 nums = [1,2,3] ,你可以选择增加 nums[1] 得到 nums = [1,3,3] 。
请你返回使 nums 严格递增 的 最少 操作次数。
我们称数组 nums 是 严格递增的 ,当它满足对于所有的 0 <= i < nums.length - 1 都有 nums[i] < nums[i+1] 。一个长度为 1 的数组是严格递增的一种特殊情况

实现代码:

int minOperations(int* nums, int numsSize){
    int pre = nums[0]+1;
    int ans=0;
    for(int i=1;i<numsSize;i++){
        if(pre < nums[i]){
            pre = nums[i]+1;
        }
        else{
            ans += pre - nums[i];
            pre++;
        }
    }
    return ans;
}

注意题目要求每一次操作增加1。

8.最小操作数使数组递增

给你一个整数数组 nums (下标从 0 开始)。每一次操作中,你可以选择数组中一个元素,并将它增加 1 。
比方说,如果 nums = [1,2,3] ,你可以选择增加 nums[1] 得到 nums = [1,3,3] 。
请你返回使 nums 严格递增 的 最少 操作次数。
我们称数组 nums 是 严格递增的 ,当它满足对于所有的 0 <= i < nums.length - 1 都有 nums[i] < nums[i+1] 。一个长度为 1 的数组是严格递增的一种特殊情况。

实现代码:

int cmp(int*a,int*b){
    return *(int*)a-*(int*)b;
}
int minIncrementForUnique(int* nums, int numsSize){
    int ans=0;
    qsort(nums,numsSize,sizeof(int),cmp);
    for(int i=1;i<numsSize;i++){
        if(nums[i]<=nums[i-1]){
            int diff = nums[i-1] - nums[i] + 1;
            nums[i]+=diff;
            ans+=diff;
        }
    }
    return ans;
}
  • 通过找到diff并让当前数+=diff,可以把之前的操作数+1体现在后面的数上,不会造成前面的数+1后,后面的数通过+1变小;

9.有效三角形的个数

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

实现代码;

int cmp(int*a,int*b){
    return *(int*)a-*(int*)b;
}
int triangleNumber(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);
    int ans=0,j,k;
    for(int i =0;i<numsSize;i++){
        j=i+1;
        k=j+1;
        while(j<numsSize){
            while(k<numsSize){
                if(nums[i]+nums[j]<=nums[k]){
                    break;
                }
                k++;
            }
            ans += k-j-1;   //k和j本身应当相差1;
            j++;
            if(j==k)k++;
        }
    }
    return ans;
}
  • 排序后利用i,j,k三层循环判断满足三角形的个数

总结

这一块好多题,不太会的题型是——最小操作递增,有效三角形个数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值