LeetCode刷题笔记【26】:贪心算法专题-4(柠檬水找零、根据身高重建队列、用最少数量的箭引爆气球)

这篇具有很好参考价值的文章主要介绍了LeetCode刷题笔记【26】:贪心算法专题-4(柠檬水找零、根据身高重建队列、用最少数量的箭引爆气球)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前置知识

参考前文

参考文章:
LeetCode刷题笔记【23】:贪心算法专题-1(分发饼干、摆动序列、最大子序和)
LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II)
LeetCode刷题笔记【25】:贪心算法专题-3(K次取反后最大化的数组和、加油站、分发糖果)

860.柠檬水找零

题目描述

LeetCode刷题笔记【26】:贪心算法专题-4(柠檬水找零、根据身高重建队列、用最少数量的箭引爆气球),LeetCode刷题笔记,leetcode,笔记,贪心算法,c++,算法

LeetCode链接:https://leetcode.cn/problems/lemonade-change/description/

解题思路

思路: 用vector<int> counter(3,0)来记录5, 10, 20元钞票的数量;
如果顾客正好给5 , ‘ c o u n t e r [ 0 ] + + ‘ ; 如果顾客给的钱 ‘ m > 5 ‘ , `counter[0]++`; 如果顾客给的钱`m>5` ,counter[0]++;如果顾客给的钱m>5‘, target = m-5;
m=15, m=5的时候分类讨论即可;
当发现counter[0]<0时返回false;
最后返回true

代码

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        vector<int> counter(3,0);
        for(int m : bills){
            int target = m-5;
            if(target==0){//1 顾客直接给5$
                counter[0]++;
            }else if(target==5){//2 顾客给10$
                counter[1]++;
                counter[0]--;
            }else if(target==15){//3 顾客给20$
                if(counter[1]>=1){//3.1 有10$
                    counter[2]++;
                    counter[1]--;
                    counter[0]--;
                }else{//3.2 没有10$
                    counter[2]++;
                    counter[0] -= 3;
                }
            }
            if(counter[0]<0 || counter[1]<0)
                return false;
        }
        return true;
    }
};

406.根据身高重建队列

题目描述

LeetCode刷题笔记【26】:贪心算法专题-4(柠檬水找零、根据身高重建队列、用最少数量的箭引爆气球),LeetCode刷题笔记,leetcode,笔记,贪心算法,c++,算法

LeetCode链接:https://leetcode.cn/problems/queue-reconstruction-by-height/description/

解题思路

先按照身高, 进行从大到小排列, 身高相同的人根据k, 从小到大排列;
然后从排列后的people数组中依次提取person, 加入ans;
加入时直接通过k, 选择空位插入;

感觉似乎有些玄学, 如果一定要总结的话, 应该着眼于sort之后插入的环节:
每次插入的这个P都是未插入的person里面最高的, 相比于已经排好队的人, 是更矮的, 所以只要从前往后数k个, 直接插入即可.

代码

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(), people.end(),[](vector<int>& a, vector<int>& b){
            return (a[0]>b[0]) || (a[0]==b[0] && a[1]<b[1]);
        });
        vector<vector<int>> ans;
        for(vector<int> person : people){
            ans.insert(ans.begin()+person[1], person);
        }
        return ans;
    }
};

452. 用最少数量的箭引爆气球

题目描述

LeetCode刷题笔记【26】:贪心算法专题-4(柠檬水找零、根据身高重建队列、用最少数量的箭引爆气球),LeetCode刷题笔记,leetcode,笔记,贪心算法,c++,算法

LeetCode链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/description/

踩坑-进行模拟

思路: 创建一个unordered_map<int,int> counter, 记录从x坐标垂直向上看, 有多少个气球
每次都选择气球最多的那个x坐标发射一支箭, 然后看击破哪些气球, 更新counter
直到气球被打完
思考了一下, 还是用vector<int> counter吧, 先遍历一下points, 求一下x轴最大值

class Solution {
private:
    vector<int> refreshX(vector<vector<int>>& points, int maxX){
        vector<int> counter(maxX+1, 0);
        for(vector<int> point : points){
            for(int x=point[0]; x<=point[1]; ++x){
                counter[x]++;
            }
        }
        return counter;
    }
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if(points.size()==0)
            return 0;
        else if(points.size()==1)
            return 1;
        int maxX=INT_MIN;
        for(vector<int> point : points){
            maxX = max(maxX, point[1]);
        }
        vector<int> counter = refreshX(points, maxX);
        // for(int i=0; i<counter.size(); ++i){
        //     cout << i << ":" << counter[i] << " " << endl;
        // }
        int ans=0;
        while(!points.empty()){
            ans ++;// 没有跳出, 那么本轮一定要射出一箭
            // 寻找本轮需要在哪个位置(shootingX)射箭
            int shootingX=0, shootingNum=INT_MIN;
            for(int i=1; i<counter.size(); ++i){
                if(counter[i] > shootingNum){
                    shootingNum = counter[i];
                    shootingX = i;
                }
            }
            for(int i=0; i<points.size(); ++i){
                points.erase(remove_if(points.begin(), points.end(), [shootingX](vector<int> p){
                    return p[0]<=shootingX && p[1]>=shootingX;
                }), points.end());
            }
            counter = refreshX(points, maxX);
        }
        return ans;
    }
};

以上写法没问题, 但是没有考虑区间为负的情况
这样的话咱们还是用unordered_map

class Solution {
private:
    map<int,int> refreshX(vector<vector<int>>& points){
        map<int,int> counter;
        for(vector<int> point : points){
            for(int x=point[0]; x<=point[1]; ++x){
                counter[x]++;
            }
        }
        return counter;
    }
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if(points.size()==0)
            return 0;
        else if(points.size()==1)
            return 1;
        bool overlapping = false;
        for(int i=0; i<points.size()-1; ++i){
            if(points[i][1]>=points[i+1][0])
                overlapping=true;
        }
        if(overlapping==false)
            return points.size();

        map<int,int> counter = refreshX(points);
        int ans=0;
        while(!points.empty()){
            ans ++;// 没有跳出, 那么本轮一定要射出一箭
            // 寻找本轮需要在哪个位置(shootingX)射箭
            // cout << "此时的counter情况是: " ;
            // for(auto& pair : counter){
            //     cout << pair.first << ":" << pair.second << " " ;
            // }
            // cout << endl;

            int shootingX=0, shootingNum=INT_MIN;
            for(auto& pair : counter){
                if(pair.second > shootingNum){
                    shootingNum = pair.second;
                    shootingX = pair.first;
                }
            }

            // cout << "shootingX= " << shootingX << endl;

            for(int i=0; i<points.size(); ++i){
                points.erase(remove_if(points.begin(), points.end(), [shootingX](vector<int> p){
                    return p[0]<=shootingX && p[1]>=shootingX;
                }), points.end());
            }
            counter = refreshX(points);
        }
        return ans;
    }
};

正确思路的贪心

以上想法很好, 也可以通过大部分案例, 就是每次射爆最多的气球;
但是对于测试用例[[9,17],[4,12],[4,8],[4,8],[7,13],[3,4],[7,12],[9,15]]而言
你先从x=8/9/10处射箭(最开始时这三点重叠气球最多), 之后就需要再射2
但是如果第一箭先x=4处射, 那么之后只用射1

所以转变思路:
① 先用左区间为index, sort points
依次从第二个气球i开始遍历, 不断更新"重叠的一组气球";
如果气球ii-1没有重叠, 那么ans++;
否则就更新i的右边界为ii-1的最小右边结(which means是"这一组重叠气球的右边界")

class Solution{
public:
    int findMinArrowShots(vector<vector<int>>& points){
        if(points.empty())
            return 0;
        sort(points.begin(), points.end(), [](vector<int>& a, vector<int>&b){
            return a[0] < b[0];
        });
        int ans=1;
        for(int i=1; i<points.size(); ++i){
            if(points[i][0] > points[i-1][1]){
                ans ++;
            }else{
                points[i][1] = min(points[i][1], points[i-1][1]);
            }
        }
        return ans;
    }
};

总结

贪心真的防不胜防, 波云诡谲, 难以捉摸;
今天第三题本来以为自己已经找到正确的贪心思路了(每次都捡能打掉最多气球的点射箭), 然而并不是;
所以个人其实认为将这些乱七八糟的东西都归到"贪心算法"中进行分类, 某种程度上并不是很严谨合理.
做的过程中多看看题解, 学习参考为主吧, 别硬磕, 伤身劳心费神.

本文参考:
柠檬水找零
根据身高重建队列
用最少数量的箭引爆气球文章来源地址https://www.toymoban.com/news/detail-704933.html

到了这里,关于LeetCode刷题笔记【26】:贪心算法专题-4(柠檬水找零、根据身高重建队列、用最少数量的箭引爆气球)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【算法刷题 | 贪心算法04】4.26(跳跃游戏、跳跃游戏||)

    【算法刷题 | 贪心算法04】4.26(跳跃游戏、跳跃游戏||)

    给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例一: 示例二: 6.2.1贪心思路 一般思路:当前位置元素如果是 3,我究竟

    2024年04月27日
    浏览(9)
  • 力扣 860. 柠檬水找零

    力扣 860. 柠檬水找零

    题目来源:https://leetcode.cn/problems/lemonade-change/description/   C++题解:由于收到的钱币只有5,10,20三种,对于5元直接收,对于10元找零1张5元,对于20元找零15元,可以找零10+5或者3*5,但是5元用处较多,所有优先找零10+5。当5元不够的时候,return false。(其实可以不记录20元的数

    2024年02月17日
    浏览(8)
  • 算法练习Day26 (Leetcode/Python-贪心算法)

    122. Best Time to Buy and Sell Stock II You are given an integer array  prices  where  prices[i]  is the price of a given stock on the  ith  day. On each day, you may decide to buy and/or sell the stock. You can only hold  at most one  share of the stock at any time. However, you can buy it then immediately sell it on the  same day . Find and return 

    2024年02月03日
    浏览(13)
  • 【每日一题】1523. 在区间范围内统计奇数数目,860. 柠檬水找零

    【每日一题】1523. 在区间范围内统计奇数数目,860. 柠檬水找零

    1523. 在区间范围内统计奇数数目 - 力扣(LeetCode) 给你两个非负整数  low  和  high  。请你返回   low   和   high   之间(包括二者)奇数的数目。 示例 1: 示例 2: 提示: 0 = low = high = 10^9          这是一道简单题。读完题目之后,要求奇数个数,最直接简单的想法就是

    2024年02月09日
    浏览(12)
  • 【贪心算法】leetcode刷题

    【贪心算法】leetcode刷题

    贪心算法无固定套路。 核心思想:先找局部最优,再扩展到全局最优。 两种思路: 1、从大到小。局部最优就是大饼干喂给胃口大的,充分利用饼干尺寸喂饱一个,全局最优就是喂饱尽可能多的小孩。 先遍历的胃口,在遍历的饼干 2、从小到大。 小饼干先喂饱小胃口 。两个

    2024年02月14日
    浏览(14)
  • LeetCode刷题笔记【30】:动态规划专题-2(不同路径、不同路径 II)

    LeetCode刷题笔记【30】:动态规划专题-2(不同路径、不同路径 II)

    参考前文 参考文章: LeetCode刷题笔记【29】:动态规划专题-1(斐波那契数、爬楼梯、使用最小花费爬楼梯) LeetCode链接:https://leetcode.cn/problems/unique-paths/description/ 动态规划 : 创建m×n的数组, 对应这个地图, 数组 val 表示 有几种方法可以走到这一格 最开始, 第一行和第一列v

    2024年02月09日
    浏览(32)
  • LeetCode刷题笔记【29】:动态规划专题-1(斐波那契数、爬楼梯、使用最小花费爬楼梯)

    LeetCode刷题笔记【29】:动态规划专题-1(斐波那契数、爬楼梯、使用最小花费爬楼梯)

    动态规划(DP,Dynamic Programming)。 其解题思路对比 贪心算法的“直接选局部最优然后推导出全局最优” ;倾向于“ 由之前的结果推导得到后续的结果 ”。 很多时候二者具有相似性,不必死扣概念。 动态规划题目的核心是dp数组的概念和构建(递推公式); 所以具体的解题步骤

    2024年02月09日
    浏览(30)
  • 【LeetCode刷题记录】数组专题

    【LeetCode刷题记录】数组专题

    说明 : 文章内容为个人的力扣刷题记录,不定时更新。 文章内容如有错误,欢迎指正。 2023-04-24 题目1. 两数之和 1. 两数之和 - 力扣(Leetcode) 方法一:暴力解法,循环遍历 C++ python 方法二:哈希表 参考1. 两数之和 - 力扣(Leetcode) 哈希表的查找时间复杂度为O(1),可以大大

    2024年02月02日
    浏览(11)
  • LeetCode刷题集(三)(26 删除有序数组中的重复项)

    LeetCode刷题集(三)(26 删除有序数组中的重复项)

    基本掌握LeetCode中的26删除有序数组中的重复项 题目描述: 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。 由于在某些语言中不能改变数组的长度,所以必须将结果放

    2023年04月17日
    浏览(42)
  • 刷题笔记26——图论二分图判定

    世界上的事情,最忌讳的就是个十全十美,你看那天上的月亮,一旦圆满了,马上就要亏厌;树上的果子,一旦熟透了,马上就要坠落。凡事总要稍留欠缺,才能持恒。 ——莫言 visited数组是在如果有环的情况下,防止在图中一直绕圈设置的,类似于剪枝操作,走过了就没必要再走一遍

    2024年02月07日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包