算法精講:貪心

介紹

貪心算法是在每一步選擇中都採取當前最好的或者最優的選擇,從而導致最終的結果是最好的或者最優的。貪心算法可以解決解決一些最優化問題,如求圖中的最小生成樹,求哈夫曼編碼。算法的思想還是比較容易理解的,難的是問題能否用貪心解決,貪心的具體策略是什麼?

翠花,上題。練過幾個題後估計你就會有自己的評估了

分發餅乾

題目來源:LeetCode 455.分發餅乾
題目描述:假設你是一位很棒的家長,想要給你的孩子們一些小餅乾。但是,每個孩子最多隻能給一塊餅乾。對每個孩子 i ,都有一個胃口值 gi ,這是能讓孩子們滿足胃口的餅乾的最小尺寸;並且每塊餅乾 j ,都有一個尺寸 sj 。如果 sj >= gi ,我們可以將這個餅乾 j 分配給孩子 i ,這個孩子會得到滿足。你的目標是儘可能滿足越多數量的孩子,並輸出這個最大數值。

注意:

你可以假設胃口值爲正。
一個小朋友最多隻能擁有一塊餅乾。

示例 1:

輸入: [1,2,3], [1,1]
輸出: 1
解釋: 
你有三個孩子和兩塊小餅乾,3個孩子的胃口值分別是:1,2,3。
雖然你有兩塊小餅乾,由於他們的尺寸都是1,你只能讓胃口值是1的孩子滿足。
所以你應該輸出1

示例 2:

輸入: [1,2], [1,2,3]
輸出: 2
解釋: 
你有兩個孩子和三塊小餅乾,2個孩子的胃口值分別是1,2。
你擁有的餅乾數量和尺寸都足以讓所有孩子滿足。
所以你應該輸出2.

題目解析:現實生活中很容易遇到這種問題哈,想想你會怎麼做,讓小孩排隊,同時將並餅乾從小到大放好,儘量用最小的餅乾滿足每個小孩,同時又能讓他們喫飽,所以這就是貪心的策略了

public class Solution {

    public int findContentChildren(int[] g, int[] s) {
        if (g.length == 0 || s.length == 0) {
            return 0;
        }
        Arrays.sort(g);
        Arrays.sort(s);
        int gIndex = 0;
        int sIndex = 0;
        while (gIndex < g.length && sIndex < s.length) {
            if (g[gIndex] <= s[sIndex]) {
                // g[gIndex]這個小孩獲得餅乾
                gIndex++;
            }
            sIndex++;
        }
        return gIndex;
    }
}

無重疊區間

題目來源:LeetCode 455.無重疊區間
題目描述:給定一個區間的集合,找到需要移除區間的最小數量,使剩餘區間互不重疊。

注意:

可以認爲區間的終點總是大於它的起點。
區間 [1,2] 和 [2,3] 的邊界相互“接觸”,但沒有相互重疊。
示例 1:

輸入: [ [1,2], [2,3], [3,4], [1,3] ]
輸出: 1
解釋: 移除 [1,3] 後,剩下的區間沒有重疊。

示例 2:

輸入: [ [1,2], [1,2], [1,2] ]
輸出: 2
解釋: 你需要移除兩個 [1,2] 來使剩下的區間沒有重疊。

示例 3:

輸入: [ [1,2], [2,3] ]
輸出: 0
解釋: 你不需要移除任何區間,因爲它們已經是無重疊的了。

題目解析:這個應該是最經典的貪心題了,這個題能變換出好多問法,例如給出一天內的課程,課程包括開始時間和結束時間,問一天最多能上多少節課。

其實這個每次選結束時間最早的課就能達到最優的效果。如果每次選開始時間最早的課能達到最優的效果嗎?

看下圖,如果每次選擇開始時間最早的課,選擇的課程爲1,3
如果每次選擇結束時間最早的課,選擇的課程爲1,4,5

在這裏插入圖片描述

public class Solution {

    public int eraseOverlapIntervals(int[][] intervals) {
        if (intervals.length == 0) {
            return 0;
        }
        // 按照每個數組的第二個元素升序排序
        Arrays.sort(intervals, (int[] o1 ,int[] o2) -> (o1[1] - o2[1]));
        int end = intervals[0][1];
        int sum = 1;
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] >= end) {
                sum++;
                end = intervals[i][1];
            }
        }
        return  intervals.length - sum;
    }
}

用最少數量的箭引爆氣球

題目地址:LeetCode 452. 用最少數量的箭引爆氣球
題目描述:在二維空間中有許多球形的氣球。對於每個氣球,提供的輸入是水平方向上,氣球直徑的開始和結束座標。由於它是水平的,所以y座標並不重要,因此只要知道開始和結束的x座標就足夠了。開始座標總是小於結束座標。平面內最多存在104個氣球。

一支弓箭可以沿着x軸從不同點完全垂直地射出。在座標x處射出一支箭,若有一個氣球的直徑的開始和結束座標爲 xstart,xend, 且滿足 xstart ≤ x ≤ xend,則該氣球會被引爆。可以射出的弓箭的數量沒有限制。 弓箭一旦被射出之後,可以無限地前進。我們想找到使得所有氣球全部被引爆,所需的弓箭的最小數量。

Example:

輸入:
[[10,16], [2,8], [1,6], [7,12]]
輸出:
2
解釋:
對於該樣例,我們可以在x = 6(射爆[2,8],[1,6]兩個氣球)和 x = 11(射爆另外兩個氣球)。

題目解析:這個題和上面的題基本上一樣,本質上就是計算最多的不重疊區間的個數,和上一題唯一的不同[1,2]和[2,3]算一個重疊空間。出題人爲了不讓刷題感到枯燥,變着法的改變問法。

public class Solution {

    public int findMinArrowShots(int[][] points) {
        if (points.length == 0) {
            return 0;
        }
        Arrays.sort(points, (int[] o1 ,int[] o2) -> (o1[1] - o2[1]));
        int end = points[0][1];
        int sum = 1;
        for (int i = 1; i < points.length; i++) {
            if (points[i][0] > end) {
                sum++;
                end = points[i][1];
            }
        }
        return sum;
    }
}

種花問題

題目地址:LeetCode 605. 種花問題
題目描述:假設你有一個很長的花壇,一部分地塊種植了花,另一部分卻沒有。可是,花卉不能種植在相鄰的地塊上,它們會爭奪水源,兩者都會死去。

給定一個花壇(表示爲一個數組包含0和1,其中0表示沒種植花,1表示種植了花),和一個數 n 。能否在不打破種植規則的情況下種入 n 朵花?能則返回True,不能則返回False。

示例 1:

輸入: flowerbed = [1,0,0,0,1], n = 1
輸出: True

示例 2:

輸入: flowerbed = [1,0,0,0,1], n = 2
輸出: False

題目解析:從左到右發現能種一直種就行。

public class Solution {

    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int sum = 0;
        for (int i = 0; i < flowerbed.length && sum < n; i++) {
            if (flowerbed[i] == 0) {
                int pre = i == 0 ? 0 : flowerbed[i - 1];
                int after = i == flowerbed.length - 1 ? 0 : flowerbed[i + 1];
                if (pre + after == 0) {
                    flowerbed[i] = 1;
                    sum++;
                }
            }
        }
        return sum == n;
    }
}

後記

最後留一道思考題,你覺得下面的題可以用貪心解決嗎?如果解決不了,該用什麼算法解決呢?
在這裏插入圖片描述

歡迎關注

在這裏插入圖片描述

參考博客

[1]https://blog.csdn.net/qq_43699339/article/details/90146817

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章