经典算法 - 贪心算法

基本定义

贪心算法或贪心思想采用贪心的策略,保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。


分配问题

问题描述:有一群孩子和一堆饼干,每个孩子有一个饥饿度,每个饼干都有一个大小。每个孩子只能吃最多一个饼干,且只有饼干的大小大于孩子的饥饿度时,这个孩子才能吃饱。求解最多有多少孩 子可以吃饱。

输入输出样例

输入: 1 3 5 6 
      1 2 3 4 5
        
输出: 2

题解

**因为饥饿度最小的孩子最容易吃饱,所以我们先考虑这个孩子。**为了尽量使得剩下的饼干可以满足饥饿度更大的孩子,所以我们应该把大于等于这个孩子饥饿度的、且大小最小的饼干给这 个孩子。满足了这个孩子之后,我们采取同样的策略,考虑剩下孩子里饥饿度最小的孩子,直到 没有满足条件的饼干存在。

简而言之,这里的贪心策略是,给剩余孩子里最小饥饿度的孩子分配最小的能饱腹的饼干至于具体实现,因为我们需要获得大小关系,一个便捷的方法就是把孩子和饼干分别排序。这样我们就可以从饥饿度最小的孩子和大小最小的饼干出发,计算有多少个对子可以满足条件。

image-20240523194110342

代码实现

import java.util.Arrays;

public class Greedy1 {
    public static int solution(int[] child,int[] cookies){
        Arrays.sort(child);
        Arrays.sort(cookies);
      	// 定义两个指针,分别指向当前的孩子和饼干,对当前的孩子和饼干进行比较
        int childNum = 0;
        int cookiesNum = 0;
        while (childNum<child.length && cookiesNum<cookies.length) {
            if (child[childNum]<=cookies[cookiesNum++]) childNum++;
        }
        return childNum;
    }
    public static void main(String[] args) {
        int[] child = {1,2,3};
        int[] cookies = {1,2,3};
        int result = solution(child,cookies);
        System.out.println(result);
    }
}

区间问题

给定多个区间,计算让这些区间互不重叠所需要移除区间的最少个数。起止相连不算重叠。

输入输出样例

输入是一个数组,数组由多个长度固定为 2 的数组组成,表示区间的开始和结尾。输出一个整数,表示需要移除的区间数量。

输入:[[1,4],[3,7],[4,6],[8,9]]
输出:1

在这个样例中,我们可以移除区间[3,7],使得剩余的区间[[1,4],[4,6],[8,9]]互不重叠。

题解

在选择要保留区间时,区间的结尾十分重要: 选择的区间结尾越小,余留给其它区间的空间就越大,就越能保留更多的区间。

因此,我们采取的贪心策略为,优先保留结尾小且不相交的区间。 具体实现方法为,先把区间按照结尾的大小进行增序排序,每次选择结尾最小且和前一个选 择的区间不重叠的区间,在样例中,排序后的数组为[[1,4],[4,6],[3,7],[8,9]]。按照我们的贪心策略,首先初始化为区间[1,4];由于 [1.4]与[3,7] 相交,我们跳过该区间;由于[1,4]与[4,6] 不相交,我们将其保留,同理,[8,9]也保留。因 此最终保留的区间为 [[1,4],[4,6],[8,9]]

image-20240523201019441

代码实现

public class Greedy2 {
    public static int solution(int[][] meetingTime){
        Arrays.sort(meetingTime,new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1]>o2[1]?1:-1;
            }
        });
        int del = 0;
        int end = meetingTime[0][1];  // 记录前面一个有效区间的结束位置
        for (int i = 1; i < meetingTime.length; i++) {
            int start = meetingTime[i][0];
            if (start<end) {
                del++;
            }else{
                end = meetingTime[i][1];
            }
        }
        return del;
    }
    public static void main(String[] args) {
        int[][] meeting = {{1,4},{3,7},{4,6},{8,9}};
        int result = solution(meeting);
        System.out.println(result);
    }
}

买股票的最佳时机问题

给定一个数组,它的第i个元素是一支给定股票第 i天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易 (多次买卖一支股票)。

注意: 你不能同时参与多笔交易 (你必须在再次购买前出售掉之前的股票)。

输入输出样例

输入:[7,1,5,3,6,4]
输出:7
解释:在第2天(股票价格=1)的时候买入,在第3天(股票价格=5)的时候卖出,这笔交易所能获得的利润为5-1=4。随后,在第4天(股票价格=3)的时候买入,在第5天(股票价格=6)的时候卖出,这笔交易所能获得利润为6-3=3

题解

这道题的贪心思想在于如果今天买,明天卖可以赚钱,那么就买入。

image-20240523205747222

代码实现

public class Greedy3 {
    public static int solution(int[] stock){
        int profit = 0;
        for(int i=0;i<stock.length-1;i++){
            if (stock[i]<stock[i+1]) {
                profit += stock[i+1]-stock[i];
            }
        }
        return profit;
    }
    public static void main(String[] args) {
        int[] stock = {7,1,5,3,6,4};
        int profit = solution(stock);
        System.out.println(profit);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mango1698

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值