leetcode高頻題筆記之貪心算法

860.檸檬水找零

在這裏插入圖片描述
在20元找零處用到了貪心,貪10元的個數,如果有就先找10元+5元,沒有再找三個5元

public class Solution {
    public boolean lemonadeChange(int[] bills) {
        int five = 0;
        int ten = 0;
        for (int bill : bills) {
            if (bill == 5) five++;//支付5元
            else if (bill == 10) {//支付10元
                if (five > 0) {//如果有5元的,找5元
                    five--;
                    ten++;
                } else {//如果沒有5元的就無法找零退出
                    return false;
                }
            } else {//支付20元
                if (ten > 0 && five > 0) {//如果有10元和5元的,找10元+5元
                    ten--;
                    five--;
                } else if (ten == 0 && five >= 3) {//如果沒有10元的有3張及以上5元的
                    five -= 3;
                } else//如果零錢不夠,退出
                    return false;
            }
        }
        return true;
    }
}

455.分發餅乾

在這裏插入圖片描述
將兩個數組進行排序
從最小胃口的孩子和最小的餅乾開始比較,如果不滿足餅乾後移一位,如果滿足計數加一,餅乾和小孩都後移一位

public class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);

        int i = 0;
        int j = 0;
        int count = 0;
        while (i < g.length && j < s.length) {
            if (g[i] <= s[j]) {
                count++;
                i++;
                j++;
            } else {
                j++;
            }
        }
        return count;
    }
}

121.買賣股票的最佳時機

在這裏插入圖片描述
遍歷數組,如果值小於當前最小值更換當前最小值,如果值大於當前最小值和最小值做差更新最大差

public class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length == 0) return 0;
        int max = 0;
        int minPrice = prices[0];
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] < minPrice) minPrice = prices[i];
            else max = Math.max(prices[i] - minPrice, max);
        }
        return max;
    }
}

122.買賣股票的最佳時機II

在這裏插入圖片描述
貪心:如果第二天大於第一天就第一天買第二天賣

public class Solution {
    public int maxProfit(int[] prices) {
      
        int res = 0;
        for (int i = 0; i < prices.length - 1; i++) {
            if (prices[i] < prices[i + 1]) res += prices[i + 1] - prices[i];
        }
        return res;
    }
}

55.跳躍遊戲

在這裏插入圖片描述

採用從後往前的貪心算法
設置一個變量爲endReachable初始化爲最後位置
從後往前遍歷數組,如果nums[i] + i >= endReachable
說明從i位置可以到達endReachable,於是將endReachable設置爲i
遍歷完數組,如果endReachable == 0,說明從第一個位置可以到達endReachable,而通過各個endReachable能到達最後位置,所以就能到達

public class Solution {
    public boolean canJump(int[] nums) {
        if (nums == null) return false;
        int endReachable = nums.length - 1;
        for (int i = nums.length - 1; i >= 0; i--) {
            if (nums[i] + i >= endReachable) {
                endReachable = i;
            }
        }
        return endReachable == 0;
    }
}

從前往後的貪心算法
如下圖,開始的位置是 2,可跳的範圍是橙色的。然後因爲 3 可以跳的更遠,所以跳到 3 的位置。
在這裏插入圖片描述
如下圖,然後現在的位置就是 3 了,能跳的範圍是橙色的,然後因爲 4 可以跳的更遠,所以下次跳到 4 的位置。
在這裏插入圖片描述
如果發生endReachable < i,即出現了0,且0無法跳過,則不能到達最後位置,返回

我們令

  • endReachable 爲當前能跳的邊界值
  • maxPosition能跳的這幾個點能跳到的最遠位置
public class Solution {
    public boolean canJump(int[] nums) {
        int endReachable = 0;//一步到達的邊界值
        int maxPosition = 0;//在範圍內可以到達的最遠你的值
        for (int i = 0; i < nums.length - 1; i++) {
            //出現0了,且還跳不過的那種,不能到達最後
            if (endReachable < i) return false;

            maxPosition = Math.max(maxPosition, nums[i] + i);

            if (i == endReachable) {
                endReachable = maxPosition;
            }
        }
        return maxPosition >= nums.length - 1;
    }
}

45.跳躍遊戲II

在這裏插入圖片描述
正向的進行貪心
如下圖,開始的位置是 2,可跳的範圍是橙色的。然後因爲 3 可以跳的更遠,所以跳到 3 的位置。
在這裏插入圖片描述
如下圖,然後現在的位置就是 3 了,能跳的範圍是橙色的,然後因爲 4 可以跳的更遠,所以下次跳到 4 的位置。
在這裏插入圖片描述
循環爲什麼到nums.length - 1就停止了,因爲

 if (i == endReachable) {
         endReachable = maxPosition;
         steps++;
 }

這一步的判斷,如果最遠步數剛好跳到了最後一個點,setps會多加一次,如案例[2,3,1,1,4]的第二步可以到最後位置,如果遍歷到nums.length - 1,則上述代碼會執行三次,結果爲3

我們令

  • endReachable 爲當前能跳的邊界值
  • maxPosition能跳的這幾個點能跳到的最遠位置
  • steps跳了的步數
public class Solution {
    public int jump(int[] nums) {
        int endReachable = 0;//一步到達的邊界值
        int maxPosition = 0;//在範圍內可以到達的最遠你的值
        int steps = 0;//步數

        for (int i = 0; i < nums.length - 1; i++) {
            maxPosition = Math.max(maxPosition, nums[i] + i);
            if (i == endReachable) {
                endReachable = maxPosition;
                steps++;
            }
        }
        return steps;
    }
}

435.無重疊區間

在這裏插入圖片描述
貪心算法

  • 將數組按結尾升序排列
  • 找出共有多少個沒有重疊的區域,記爲count
  • 總數-count得到需要移除的數目
public 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) {
                return o1[1] - o2[1];
            }
        });

        //第一段的結尾
        int x_end = intervals[0][1];
        //至少有1段
        int count = 1;
        for (int[] cur : intervals) {
            if (cur[0] >= x_end) {
                x_end = cur[1];
                count++;
            }
        }
        return intervals.length - count;
    }
}

452.用最少數量的箭引爆氣球

在這裏插入圖片描述
問題讀起來聽繞口的,仔細分析後其實就是求:不重疊區間的個數
無重疊區間問題中的求不重疊區間 個數有一點點不同,邊界值可以取等號,如[1,2]和[2,3]是存在重疊的
所以cur[0] >= x_end的條件需要改成cur[0] > x_end

public class Solution {
    //問題轉化爲:求獨立區間的個數
    public int findMinArrowShots(int[][] points) {
        if (points.length == 0) return 0;
        Arrays.sort(points, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        //獨立區間個數,至少有一個
        int count = 1;
        //第一個氣球的x_end
        int x_end = points[0][1];
        for (int[] cur : points) {
            if (cur[0] > x_end) {
                count++;
                x_end = cur[1];
            }
        }
        return count;
    }
}

406.根據身高重建隊列

在這裏插入圖片描述
解法太美麗,可能解釋不清楚,官方題解看圖就懂了

首先,將數組按身高降序排列,如果身高相同的按k大小升序排列

然後,按照k的大小進行插入

下插入的最大的數字是符合k的定義的,再插入次大的數字,最大的數字後移,因爲小的數在大的數面前是看不見的,所以不影響大的數的k的定義,因爲是由大到小排列的,所以可以直接插入

public class Solution {
    public int[][] reconstructQueue(int[][] people) {
        if (people == null || people.length == 0 || people[0].length == 0) return people;

        ///身高按降序,身高相同時,次數按升序
        Arrays.sort(people, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0] == o2[0] ? o1[1] - o2[1] : o2[0] - o1[0];
            }
        });

        //插入
        List<int[]> queue = new ArrayList<>();
        for (int[] p : people) {
            queue.add(p[1], p);
        }
        return queue.toArray(new int[queue.size()][]);
    }
}

605.種花問題

在這裏插入圖片描述
貪心+常數優化
依次遍歷數組,如果不爲1,判斷求一個數和後一個數是否都爲0,如果是將值改爲1,並計數+1,當計數等於n時就退出不再繼續

public class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {

        int len = flowerbed.length;
        int count = 0;
        for (int i = 0; i < len && count < n; i++) {
            if (flowerbed[i] == 1) continue;
            int pre = i == 0 ? 0 : flowerbed[i - 1];
            int next = i == len - 1 ? 0 : flowerbed[i + 1];
            if (pre == 0 && next == 0) {
                flowerbed[i] = 1;
                count++;
            }
        }
        return count == n;
    }
}

392.判斷子序列

在這裏插入圖片描述
遍歷s,將s的字符在t中進行匹配,每次匹配從上一個匹配到的數的後一位開始,如果出現沒有匹配到,則不是子串

public class Solution {
    public boolean isSubsequence(String s, String t) {
        int index = -1;
        for (char c : s.toCharArray()) {
            index = t.indexOf(c, index + 1);
            if (index == -1) return false;
        }
        return true;
    }
}

665.非遞減數列

在這裏插入圖片描述
依次遍歷數組,如果nums[i] < nums[i - 1],則需要進行修改,修改的情況有兩種

  • 修改nums[i]的值,判斷一下nums[i-2]是否大於nums[i],如果大於,說明nums[i]纔是錯誤的,將值改爲nums[i-1]的值
  • 修改nums[i-1]的值,將nums[i]賦值給nums[i-1]
public class Solution {

    public boolean checkPossibility(int[] nums) {
        if (nums.length < 2) return true;
        int count = 0;
        for (int i = 1; i < nums.length && count < 2; i++) {
            if (nums[i] >= nums[i - 1]) continue;
            count++;
            if (i - 2 >= 0 && nums[i] < nums[i - 2]) {
                nums[i] = nums[i - 1];
            } else {
                nums[i - 1] = nums[i];
            }
        }
        return count <= 1;
    }
}

53.最大子序和

在這裏插入圖片描述
每一步都選擇最佳方案,到最後就是全局最優的方案。

public class Solution {
    public int maxSubArray(int[] nums) {
        int curMax = nums[0];
        int trueMax = nums[0];
        for (int i = 1; i < nums.length; i++) {
            curMax = Math.max(nums[i], curMax + nums[i]);
            trueMax = Math.max(curMax, trueMax);
        }
        return trueMax;
    }
}

763.劃分字母區間

在這裏插入圖片描述
將每個字母的最後一次出現下標存放在last數組中
依次遍歷字符串,並更新訪問過的字符的最大last值
當遍歷到i==last時,說明一個區域劃分完了,記錄位置並存儲

public class Solution {
    public List<Integer> partitionLabels(String S) {
        List<Integer> res = new ArrayList<>();

        int[] last = new int[26];
        //記錄每個字母最後出現的位置
        for (int i = 0; i < S.length(); i++) {
            last[S.charAt(i) - 'a'] = i;
        }
        int curend = 0;
        int newfirst = 0;
        for (int i = 0; i < S.length(); i++) {
            curend = Math.max(curend, last[S.charAt(i) - 'a']);
            if (i == curend) {
                res.add(i - newfirst + 1);
                newfirst = i + 1;
            }
        }
        return res;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章