贪心算法专题

目录

🌞贪心算法概念

🌻算法思想

🌻基本思路

🌂贪心例题

☔选择排序

☔平衡字符串

☔买卖股票的最佳时机Ⅱ

☔跳跃游戏

☔最多可以参加的会议数目

☔无重叠区间

😀总结

🌈贪心策略

🌈该算法存在的问题


🌞贪心算法概念

🌻算法思想

贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素。

当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。运用贪心策略在每一次转化时都取得了最优解。问题的最优子结构性质是该问题可用贪心算法求解的关键特征。贪心算法的每一次操作都对结果产生直接影响。

🌻基本思路

从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止。

🌂贪心例题

☔选择排序

选择排序是最经典的贪心算法问题,我们可以从选择排序入手,来了解贪心算法的代码。

public static void selectSort(int[] array) {
    for (int i = 0; i < array.length; i++) {
        //记录 最小值的下标
        int minIndex = i;
        //贪心:每次从未排序数组中找到最小值
        for ( int j = i+1; j < array.length; j++) {
            if(array[j] < array[minIndex]) {
                minIndex = j;
            }
        }
        //把最小值放在没排序的最前端
        swap(array,minIndex,i);
    }
}
private static void swap(int[] array,int i,int j) {
    int tmp = array[i];
    array[i] = array[j];
    array[j] = tmp;
}

☔平衡字符串

题目

        在一个 平衡字符串 中,'L' 和 'R' 字符的数量是相同的。

        给你一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。

示例

        输入:s = "RLRRLLRLRL"

        输出:4

        解释:s 可以分割为 "RL"、"RRLL"、"RL"、"RL" ,每个子字符串中都包含相同数量的 'L' 和 'R' 。

贪心策略

        如果出现平衡状态,如"RRLL"、"RL",立刻分割并计数。

class Solution {
    public int balancedStringSplit(String s) {
        int count=0;
        int balance=0;
        for(int i=0;i<s.length();++i){
            //如果出现R就++出现L就--
            if(s.charAt(i)=='R'){
                balance++;
            }else{
                balance--;
            }
            //平衡就意味着L和R个数相等,即banlance为0了
            if(balance==0){
                //计数
                count++;
            }
        }
        return count;
    }
}

☔买卖股票的最佳时机Ⅱ

💧这道题的题目是不是有点熟悉,买卖股票的最佳时机Ⅰ是动态规划算法专题里的例题。

题目

        给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

        在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

        返回 你能获得的 最大 利润 。

示例

        输入:prices = [7,1,5,3,6,4]

        输出:7

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

贪心策略

        只要相比前一天,股票涨了,那就在进行买卖。

class Solution {
    public int maxProfit(int[] prices) {
        int count=0;
        for(int i=1;i<prices.length;++i){
            //只要股票能涨价,咱就买卖
            if(prices[i-1]<prices[i]){
                count+=prices[i]-prices[i-1];
            }
        }
        return count;
    }
}

☔跳跃游戏

题目

        给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。

        数组中的每个元素代表你在该位置可以跳跃的最大长度。

        判断你是否能够到达最后一个下标。

示例

        输入:nums = [2,3,1,1,4]

        输出:true

        解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

贪心策略

        向后遍历数组,每一步都更新可以到达的最远位置,如果最远位置包含了最后的元素,那么就返回true

class Solution {
    public boolean canJump(int[] nums) {
        int max=0;
        for(int i=0;i<nums.length;++i){
            //如果跳的到第i点
            if(max>=i){
                //那就更新最远跳跃距离
                max=Math.max(max,i+nums[i]);
                //最远跳跃距离包含最后一点,就可以直接返回true了
                if(max>=nums.length-1){
                    return true;
                }
            //跳不到第i点那就永远也跳不过去
            }else{
                return false;
            }
        }
        return true;
    }
}

☔最多可以参加的会议数目

题目

        给你一个数组 events,其中 events[i] = [startDayi, endDayi] ,表示会议 i 开始于 startDayi ,结束于 endDayi 。

        你可以在满足 startDayi 

        请你返回你可以参加的 最大 会议数目。

示例

        输入:events = [[1,2],[2,3],[3,4]]

        输出:3

        解释:你可以参加所有的三个会议。安排会议的一种方案如上图。

                        第 1 天参加第一个会议。

                        第 2 天参加第二个会议。

                        第 3 天参加第三个会议。

示例

        输入:events= [[1,2],[2,3],[3,4],[1,2]]

        输出:4

贪心策略

        优先选择会议结束时间早的

class Solution {
    public int maxEvents(int[][] events) {
        //按开始时间排序
        Arrays.sort(events, (a, b)->(a[0]-b[0]));
        //优先队列(小根堆),存会议结束的时间
        PriorityQueue<Integer> queue = new PriorityQueue<>();

        int result = 0;
        int start = events[0][0];
        int index = 0;
        
        //还有会议没开始或还有会议没结束,就进入循环
        while(index < events.length || !queue.isEmpty()){
            //把开始时间相同的,放入堆中,比较结束时间,谁先结束就选谁
            while(index < events.length && events[index][0] == start){
                queue.offer(events[index][1]);
                index++;
            }
            //把开始时间之前已经结束的删除
            while(!queue.isEmpty() && queue.peek() < start){
                queue.poll();
            }

            //如果队列不空,还有会议没结束,那么队头,就是结束时间最早的会议,参加他
            if(!queue.isEmpty()){
                queue.poll();
                result++;
            }
            //下一天
            start++;
        }
        return result;
    }
}

☔无重叠区间

题目

        给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 。 

示例 :

        输入: intervals = [[1,2],[2,3],[3,4],[1,3]]

        输出: 1

        解释: 移除 [1,3] 后,剩下的区间没有重叠。

贪心策略

        如果区间之间冲突,就删除占用区间最大的那个

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        //按照起始位置递增排序
        Arrays.sort(intervals, (a,b)->a[0]-b[0]);
        int num=0;
        int i=0;
        for(int j=1;j<intervals.length;++j){
            if(intervals[j][0]>=intervals[i][1]){
                //区间之间不冲突
                i=j;
            }else{
                if(intervals[j][1]<intervals[i][1]){
                    i=j;
                }
                num++;
            }
        }
        return num;
    }
}

😀总结

🌈贪心策略

1. 建立数学模型来描述问题;

2. 把求解的问题分成若干个子问题;

3. 对每一子问题求解,得到子问题的局部最优解;

4. 把子问题的局部最优解合成原来解问题的一个解。

用白话说,即假设一个问题比较复杂,暂时找不到全局最优解,那么我们可以考虑把原问题拆成几个小问题,分别求每个小问题的最优解,再把这些“局部最优解”叠起来,就“当作”整个问题的最优解了。

🌈该算法存在的问题

不能保证求得的最后解是最佳的

不能用来求最大值或最小值的问题

只能求满足某些约束条件的可行解的范围

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值