算法通关村--原来贪心如此简单

难以理解的贪心算法

贪心算法不好解释,越是权威的语言解释就越难懂。用一句话来说就是“只可意会,不能言传”。而且贪心的题目没有固定的套路,一题一样,好在大部分贪心算法的题都不是特别难,因此贪心的学习方法就是“直接做题,不考虑贪不贪心”。

贪心算法就是在对问题进行求解时,在每一步选择中都采取最好的或者最优的选择,从而希望能够导致结果是最好的或者最优的算法;贪心算法所得到的结果不一定是最优解,但都是相对近似的最优解的结果。

贪心算法不能保证一定能得到最优解,但是对很多问题确实可以得到最优解。

贪心常见的经典应用场景如下:

1.排序问题:选择排序、拓扑排序

2.优先队列:堆排序

3.赫夫曼压缩编码

4.图里的Prim、Fruskal和Dijkstra算法

5.硬币找零问题

6.分数背包问题

7.并查集的按大小或者高度合并问题或者排名

8.任务调度部分场景

9.一些复杂问题的近似算法

贪心问题的举例

分发饼干

LeetCode455:

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

示例1:

输入:g = [1,2,3] , s = [1,1]

输出:1

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

示例2:

输入:g = [1,2] , s = [1,2,3]

输出:2

解释:你有两个孩子和三块小饼干,2个孩子的胃口值分别是:1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足,所以你应该输出2。

思路:

要满足小孩的胃口,扼要避免饼干浪费,可以将大饼干优先满足给胃口大的。

先将饼干数组和小孩数组排序。然后从后遍历小孩数组,用大饼干满足胃口大的,并且满足小孩数量就解决了。

public static int findContentChildren(int[] g,int[] s){
        Arrays.sort(g);
        Arrays.sort(s);
        int count = 0;//用于计数
        int start = s.length - 1;
        for (int index = g.length - 1;index >= 0; index--){
            if (start >=0 && g[index] <= s[start]){
                start--;
                count++;
            }
        }
        return count;
    }

柠檬水找零

LeetCode860:

在柠檬水摊上,每一杯柠檬水的售价为5美元,顾客排队购买你的产品,(按账单bills支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你支付5美元、10美元或者20美元。你必须给每个顾客正确的找零,也就是说净交易是每位顾客向你支付5美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组bills,其中bills[i]是第i位顾客付的账。如果你能给每位顾客正确地找零,返回true,否则返回false。

示例1:

输入:bills = [5,5,5,10,20]

输出:true

解释:前3位顾客那里,我们按顺序收取3张5美元。第4位顾客那里,我们收取一张10美元的钞票,并返还5美元。第5位顾客那里,我们找还一张10美元的钞票和一张5美元的钞票。由于所有顾客都得到了正确的找零,所以我们输出true。

示例2:

输入:bills = [5,5,10,10,20]

输出:true

解释:前2位顾客那里,我们按顺序收取2张5美元。对于接下来的2位顾客,我们收取一张10美元的钞票,然后返还5美元。对于最后一位顾客,我们无法退回15美元,因为我们现在只有两张10美元的钞票。由于不是每位顾客都得到了正确的找零,所以答案是false。

思路:

当收取5美元时,直接手下即可。

当收取10美元时,需要找零5美元,如果没有5美元面值的钞票,则无法正确找零。

当收取20美元时,需要找零15美元,有两种找零方式:1.一张10美元一张5美元;2.三张5美元。如果两种方式都没有,则无法正确找零。当正确找零时,尽量按第一张方式找零,因为使用5美元的时候比使用10美元的时候多。

public static boolean lemonadeChange(int[] bills){
        int five = 0;
        int ten = 0;
        for (int bill : bills){
            if (bill == 5){
                five++;
            }else if (bill == 10){
                //若无5元,直接返回false
                if (five == 0){
                    return false;
                }
                five--;
                ten++;
            }else {
                //5美元,10美元都有,优先扣除
                if (five > 0 && ten > 0){
                    five--;
                    ten--;
                }else if (five >= 3){
                    five -= 3;
                }else {
                    return false;
                }
            }
        }
        return true;
    }

分发糖果

LeetCode135:

n个孩子站成一排。给你一个整数数组ratings表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

        每个孩子至少分配到1个糖果。

        相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的最少糖果数目。

示例1:

输入:ratings =  [1,0,2]

输出:5

解释:你可以分别给第一个、第二个孩子分发2、1、2颗糖果。

示例2:

输入:ratings = [1,2,2]

输出:4

解释:你可以分别给第一个、第二个、第三个孩子分发1、2、1颗糖果。第三个孩子只要得到1颗糖果,这满足题面中的两个条件。

思路:

每个孩子至少一个糖果,当后一个孩子比前一个孩子积分多时,糖果就加1,

public static int candy(int[] ratings){
        int[] candyVec = new int[ratings.length];
        candyVec[0] = 1;
        for (int i = 1; i < ratings.length; i++){
            if (ratings[i] > ratings[i-1]){
                candyVec[i] = candyVec[i-1] + 1;
            }else {
                candyVec[i] = 1;
            }
        }
        for (int i = ratings.length - 2; i >= 0; i--){
            if (ratings[i] > ratings[i+1]){
                candyVec[i] = Math.max(candyVec[i],candyVec[i+1] + 1);
            }
        }
        int ans = 0;
        for (int s : candyVec){
            ans += s;
        }
        return ans;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值