貪心算法習題講解


實驗室的算法課程,今天輪到我給師弟師妹們講貪心算法,順便也復習一下。

貪心算法這個名字聽起來唬人,其實通常是比較簡單的。雖然通常貪心算法的實現非常容易,但是,一個問題是否能夠使用貪心算法,是一定要小心的。本文課通過LeetCode的一些習題,我們來回顧一下貪心算法。

LeetCode 455. Assign Cookies

題目描述

假設你是一位很棒的家長,想要給你的孩子們一些小餅干。但是,每個孩子最多只能給一塊餅干。對每個孩子 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.

解題思路

示例2中,可以很輕易的看出,第二塊餅干給第二個小朋友,第一塊餅干給第一個小朋友,就可以使得兩個小朋友都開心。

如果小朋友很多的話,或者餅干很多話,可能不能夠一眼看出怎么分配才能使小朋友都開心,那么怎么才能夠使得更多的小朋友開心呢?

策略:最大的餅干給最貪心的小朋友。

每次都要取得最大的餅干,所以要用到排序算法。在Java中可以直接利用Arrays.sort(int[])進行排序的操作。其他的語言我不是很清楚,如果沒有排序的API,也可以自己來實現排序算法。可以參考我們一起來排序——使用Java語言優雅地實現常用排序算法

通常,貪心算法和排序是分不開的

代碼實現

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        int res = 0;
        //先對數組進行排序
        Arrays.sort(g);
        Arrays.sort(s);
        
        //定義兩個變量,記錄數組的下標
        int i = s.length - 1;
        int j = g.length - 1;
        
        while(i>=0 && j>=0){
            //如果餅干大小大於等於小朋友的胃口,則認為這塊餅干可以使得小朋友滿足。
            if(s[i] >= g[j]){
                res++;
                i--;
                j--;
            }else{
                j--;
            }
        }
        
        return res;
    }
}

時間復雜度分析:while循環的時間復雜度為O(n),調用API進行排序的時間復雜度為O(nlogn),所以整體時間復雜度為O(nlogn)。

LeetCode 122. Best Time to Buy and Sell Stock II

題目描述

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。

設計一個算法來計算你所能獲取的最大利潤。你可以盡可能地完成更多的交易(多次買賣一支股票)。

注意:你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。

示例 1:

輸入: [7,1,5,3,6,4]

輸出: 7

解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 3 天(股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。

隨后,在第 4 天(股票價格 = 3)的時候買入,在第 5 天(股票價格 = 6)的時候賣出, 這筆交易所能獲得利潤 = 6-3 = 3 。

示例 2:

輸入: [1,2,3,4,5]

輸出: 4

解釋: 在第 1 天(股票價格 = 1)的時候買入,在第 5 天 (股票價格 = 5)的時候賣出, 這筆交易所能獲得利潤 = 5-1 = 4 。

注意你不能在第 1 天和第 2 天接連購買股票,之后再將它們賣出。

因為這樣屬於同時參與了多筆交易,你必須在再次購買前出售掉之前的股票。

示例 3:

輸入: [7,6,4,3,1]

輸出: 0

解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。

解題思路

貪心算法:只要在增長就累加到當前的利潤。

代碼實現

class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null || prices.length==0){
            return 0;
        }
        int res = 0;
        for(int i=1;i<prices.length;i++){
            //如果當前值大於前一個值,也就是說賣出股票可以獲得利潤
            if(prices[i] - prices[i-1] > 0){
                res += prices[i] - prices[i-1];
            }
        }
        return res;
    }
}

LeetCode 435. Non-overlapping Intervals

題目描述

給定一個區間的集合,找到需要移除區間的最小數量,使剩余區間互不重疊。

注意

可以認為區間的終點總是大於它的起點

區間 [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

解釋: 你不需要移除任何區間,因為它們已經是無重疊的了。

解題思路

移除區間的最小數量,也就是說最多保留多少個區間,可以讓這些區間之間互不重疊。

貪心算法:按照區間的結尾進行排序,每次選擇結尾最小的,且和前一個區間不重疊的區間。

代碼實現

這里使用到了二維數組的排序,Java中沒有可以直接使用的API,需要用到Arrays下面的public static <T> void sort(T[] a, Comparator<? super T> c),需要重寫創建一個Comparator並重寫compare方法。

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if(intervals==null || intervals.length == 0){
            return 0;
        }
        //排序
        Arrays.sort(intervals,new Comparator<int[]>(){
            
            @Override
            public int compare(int[] o1, int[] o2){
                if(o1[1] != o2[1]){
                    return o1[1]-o2[1];
                }
                return o1[0]-o2[0];
            }
        });
        
        int res = 1;
        int pre = 0;
        for(int i=1;i<intervals.length;i++){
            if(intervals[i][0] >= intervals[pre][1]){
                res++;
                pre=i;
            }
        }
        return intervals.length - res;
        
    }
}

總結

貪心選擇性質:在求解一個最優化的問題中,使用貪心的方式選擇了一組內容之后,不會影響剩下的子問題的求解。

如果一個問題滿足貪心選擇性質,則可以使用貪心算法。

證明一個問題是否滿足貪心選擇性質,可以使用反證法和數學歸納法,通常證明過程不簡單。在平時的練習過程中,可以使用舉反例的方法進行驗證,如果舉不出一個反例,則可以嘗試使用貪心算法來求解,通常也會得到正確的結果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM