贪心算法(一)

news2025/1/24 18:03:43

🖊作者 : D. Star.
📘专栏 : 算法小能手
😆今日提问 : 国庆去哪里打卡了呢?
😆今日分享 : 武功山风景打卡–双云海
武功山

文章目录

  • 🌻贪心算法的思想
  • 🌻贪心算法的基本思路
    • 📖给大家讲一个小故事理解一下吧~
    • 📖再来个题目,理解一下吧~
      • 第一题:力扣的860题
        • 🔎解题思路:
        • 🔎具体代码如下:
        • 🔎总结:
      • 第二题:力扣的2208题
        • 🔎解题思路:
        • 🔎具体代码如下:
        • 🔎总结:
      • 第三题:力扣的179题
        • 解题思路:
        • 具体代码如下:
        • 总结:
    • 家人们,点个![请添加图片描述](https://img-blog.csdnimg.cn/11dae7d2dd1b46b2b021edaccee67cf1.jpeg)再走呗~

刚开始听到这个名称的时候,心里充满疑惑。心想:咋还有那么奇葩的名字,说的跟人一样…了解了它的核心思想后,我发现这个名字很符合它的特性。

🌻贪心算法的思想

贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。就像人一样,贪心时是顾不上大局的,只能看见眼前的利益,将自己的利益最大化。

🌻贪心算法的基本思路

从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到算法中的某一步不能再继续前进时,算法停止。

该算法存在问题:

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

  2. 不能用来求最大或最小解问题;

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

📖给大家讲一个小故事理解一下吧~

  • 从前有一只小海龟在一座孤岛上,和他的兄弟姐妹们刚从蛋里孵化出来,正准备爬到海里觅食。这时候,海龟妈妈说,谁第一个下海的,有零食大礼包奖励哦~

  • 假设小海龟们可以爬1分钟/米,全长10米的路程,最优解是10分钟不停歇的爬完。

  • 刚开始,小海龟们都兴致高昂,对零食大礼包势在必得。但是没爬一会儿,就有海龟放弃挣扎了等着晚上涨潮再下海,有的海龟则是一直赶路。咱们的小海龟哭着叫累呀,没办法,他在前进和摆烂中间,选择了摆烂一小会儿,前进一大步的策略。他休息10s,爬1分钟。最终他虽然不是第一,但整体来说,也是名列前茅的。
    分析:上面的小故事中,小海龟在考虑到自身条件的情况下,选择了贪心解法,满足了自身的最大利益,虽然不是最快的,但是也达到了下海的目的并且速度也不差。

📖再来个题目,理解一下吧~

第一题:力扣的860题

力扣的860题

题目:

  • 在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。
  • 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。
  • 注意,一开始你手头没有任何零钱。
    给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

示例 1:

输入:bills = [5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。

示例 2:

输入:bills = [5,5,10,10,20]
输出:false
解释:
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零,所以答案是 false。

🔎解题思路:

在这里插入图片描述

在这里插入图片描述


🔎具体代码如下:
public static boolean lemonadeChange2(int[] bills) {
        int five = 0;
        int ten = 0;
        for (int x : bills) {
            if (x == 5) {
                five++;
                continue;
            } else if (x == 10) {
                if (five == 0) return false;
                five--;
                ten++;
            } else if (x == 20) {
                if (five != 0 && ten != 0) {
                    five--;
                    ten--;
                } else if (five >= 3) {
                    five -= 3;
                } else return false;
            }
        }
        return true;
    }
🔎总结:

我觉得这个题目 巧在 5元、10元、20元都是纸票子, 难在 20元有两种匹配方式。而10元+5元的才是最优配对方式。这个题目我自己做的时候,想复杂了。想不到这种又简便又通透的方法,真心崇拜贪心算法~


第二题:力扣的2208题

力扣的2208题

题目 :

  • 给你一个正整数数组 nums 。每一次操作中,你可以从 nums 中选择 任意 一个数并将它减小到 恰好 一半。(注意,在后续操作中你可以对减半过的数继续执行操作)
  • 请你返回将 nums 数组和 至少 减少一半的 最少 操作数。

示例1:

输入:nums = [5,19,8,1]
输出:3
解释:初始 nums 的和为 5 + 19 + 8 + 1 = 33 。
以下是将数组和减少至少一半的一种方法:
选择数字 19 并减小为 9.5 。
选择数字 9.5 并减小为 4.75 。
选择数字 8 并减小为 4 。
最终数组为 [5, 4.75, 4, 1] ,和为 5 + 4.75 + 4 + 1 = 14.75 。
nums 的和减小了 33 - 14.75 = 18.25 ,减小的部分超过了初始数组和的一半,18.25 >= 33/2 = 16.5 。
我们需要 3 个操作实现题目要求,所以返回 3 。
可以证明,无法通过少于 3 个操作使数组和减少至少一半。

示例2:

输入:nums = [3,8,20]
输出:3
解释:初始 nums 的和为 3 + 8 + 20 = 31 。
以下是将数组和减少至少一半的一种方法:
选择数字 20 并减小为 10 。
选择数字 10 并减小为 5 。
选择数字 3 并减小为 1.5 。
最终数组为 [1.5, 8, 5] ,和为 1.5 + 8 + 5 = 14.5 。
nums 的和减小了 31 - 14.5 = 16.5 ,减小的部分超过了初始数组和的一半, 16.5 >= 31/2 = 15.5 。
我们需要 3 个操作实现题目要求,所以返回 3 。
可以证明,无法通过少于 3 个操作使数组和减少至少一半。

🔎解题思路:

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/345f3455a2a449b7b82e55e4f010854a.png
)

🔎具体代码如下:
public int halveArray(int[] nums) {
        //题目的意思是说,通过减半操作,减半后的数组和要比原数组小,并且小一半及以上
        PriorityQueue<Double> heap = new PriorityQueue<>((a,b) -> b.compareTo(a));//大根堆
        double sum = 0.0;
        int number = 0;
        //计算原数组和
        for(int x:nums){
            heap.offer((double)x);
            sum+=x;
        }
        sum/=2.0;
        //判断sum<=0时,满足减少一半
        while(sum>0){
            double t = heap.poll()/2.0;//将最大的数字拿出来/2,
            number++;
            heap.offer(t);//再塞回去
            sum-=t;//将sum减去少掉的部分
        }
        return number;
    }
🔎总结:

我做这个题目的时候,觉得最难搞的就是 数据类型问题 ,原数组是整型,而减半之后就有可能是小数(double)了,我就想着如何将原数组复制出一个新的double数组,但是后面每次减半,我都要排列一下数组的大小顺序,导致我写的代码 超出了时间限制 。看了老师给的贪心解法后,直呼牛逼。由于对Java的不熟悉,不晓得还有一个PriorityQueue(自动排序)的数组结构,这个结构最牛逼的地方就是它可以根据我们的需要 自动排序,顶端的就是最大的数字!!!真的,你懂我的心情嘛?省了我好多事儿!!!

PriorityQueue的用法:
最大的优势就是:可插入,可移出,并且可以在插入常量的同时自动排序
创建一个降序数组:PriorityQueue<数据类型> 名称 = new PriorityQueue((a,b) -> b.compareTo(a)) //b<a
创建一个升序数组:PriorityQueue<数据类型> 名称 = new PriorityQueue((a,b) -> a.compareTo(b)) //a<b

第三题:力扣的179题

力扣的179题

题目:
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数。

示例 1:

输入:nums = [10,2]
输出:“210”

示例 2:

输入:nums = [3,30,34,5,9]
输出:“9534330”

解题思路:

在这里插入图片描述

具体代码如下:
 public String largestNumber(int[] nums) {
        int n = nums.length;//数组长度
        String[] arr = new String[n];//先建立一个字符串数组
        //将整型数组的内容全部拷贝到arr中
        for (int i = 0; i < n; i++) {
            arr[i] = "" + nums[i];
        }
        //排序
        Arrays.sort(arr, (a, b) -> {
            return (b + a).compareTo(a + b);
        });
        //提取结果
        StringBuffer str = new StringBuffer();
        for (int i = 0; i < n; i++) {
            str.append(arr[i]);//将字符串中的数字连接起来
        }
        //返回
        if (nums[0] == 0) return "0";
        return str.toString();
    }
总结:

这题的难点,我认为在于如何将“最大的”那个数字移到前面(这里的最大不是指数字值最大,而是使得这一串数字最大的 数字)。而解题最巧妙的点,在于Arrays.sort()这个排列我们可以将两个数字连接比较连接后的阿斯科码值,将大的排序放在前面。最后再用StringBuffer将这些字符串连接起来。


感谢家人的阅读,若有不准确的地方 欢迎在评论区指正!

家人们,点个请添加图片描述再走呗~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1094491.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高可用eureka服务注册与发现代码例子

代码 Eureka server 1 pom.xml <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.clou…

Python开源项目周排行 2023年第36周

#2023年第36周2023年10月14日1书生・浦语灵笔图文混合创作大模型。基于书生・浦语大语言模型研发的视觉 - 语言大模型&#xff0c;提供出色的图文理解和创作能力&#xff0c;具有多项优势&#xff1a; 图文交错创作: 浦语・灵笔可以为用户打造图文并貌的专属文章。生成的文章文…

Go语言入门心法(五): 函数

一: go语言函数认知 Go语言入门心法(一): 基础语法 Go语言入门心法(二): 结构体 Go语言入门心法(三): 接口 忙着去耍帅,后期补上..........

从不同的正态分布中抽取随机数randn()函数

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 从不同的正态分布中抽取随机数 randn()函数 [太阳]选择题 下列选项对代码最后运行结果描述错误的是&#xff1f; import numpy as np print("【执行】np.random.randn()") print(np.…

《UnityShader入门精要》学习5

Unity中的基础光照 从宏观上来说&#xff0c;渲染包含了两大部分&#xff1a;决定一个像素的可见性&#xff0c;决定这个像素上的光照计算 我们是如何看到这个世界的 通常来讲&#xff0c;我们要模拟真实的光照环境来生成一张图像&#xff0c;需要考虑3种物理现象。 首先&a…

13年测试老鸟总结,真实性能测试如何做?性能测试完整流程+细节...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试什么时候…

【HttpRunner】接口自动化测试框架

简介 2018年python开发者大会上&#xff0c;了解到HttpRuuner开源自动化测试框架&#xff0c;采用YAML/JSON格式管理用例&#xff0c;能录制和转换生成用例功能&#xff0c;充分做到用例与测试代码分离&#xff0c;相比excel维护测试场景数据更加简洁。在此&#xff0c;利用业…

傅里叶变换和其图像处理中的应用

以下部分文字资料整合于网络&#xff0c;本文仅供自己学习用&#xff01; 一、为什么要在频域进行图像处理&#xff1f; 一些在空间域表述困难的增强任务&#xff0c;在频率域中变得非常普通 滤波在频率域更为直观&#xff0c;你想想嘛&#xff0c;所谓滤波&#xff0c;就是…

第 115 场 LeetCode 双周赛题解

A 上一个遍历的整数 模拟 class Solution { public:vector<int> lastVisitedIntegers(vector<string> &words) {vector<int> res;vector<int> li;for (int i 0, n words.size(); i < n;) {if (words[i] ! "prev")li.push_back(stoi…

数据结构与算法——线性查找法

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

冲刺十五届蓝桥杯P0005单词分析

文章目录 题目分析代码 题目 单词分析 分析 统计字符串中字母出现的次数&#xff0c;可以采用哈希表&#xff0c;代码采用的是数组来存储字符&#xff0c;将字符-97&#xff0c;得到对应的数组下标&#xff0c;将对应下标的数组&#xff1b;找到数组元素最大的下标&#xff…

微店店铺所有商品数据接口,微店整店商品数据接口,微店店铺商品数据接口,微店API接口

微店店铺所有商品数据接口是一种允许开发者在其应用程序中调用微店店铺所有商品数据的API接口。利用这一接口&#xff0c;开发者可以获取微店店铺的所有商品信息&#xff0c;包括商品名称、价格、介绍、图片等。 其主要用途是帮助开发者进行各种业务场景的构建&#xff0c;例如…

如果不封车,坚持冬天骑行应该注意些什么?

亲爱的骑行爱好者们&#xff0c;你们好&#xff01;随着秋天的脚步渐行渐远&#xff0c;冬天也不远了。对于热爱骑行的你们来说&#xff0c;秋天的骑行是一种享受&#xff0c;而冬天的骑行则是一种挑战。那么&#xff0c;如果你打算在秋天骑行不封车&#xff0c;坚持过冬天&…

小解C语言文件编译过程【linux】

小解C语言文件编译过程【linux】 库动态库静态库 C语言文件 程序编译过程整体预处理编译汇编链接动态链接静态链接两种方法对比 库 看到标题是文件编译过程 但是开头却是库&#xff0c;这可不是挂羊头卖狗肉&#xff0c;而是因为库也是代码不可缺少的一部分&#xff0c;并且在…

运维 | 如何查看端口或程序占用情况 | linux

运维 | 如何查看端口或程序占用情况 | linux 前言 本期主要介绍了 LINUX 中如何查看某个端口或程序的使用情况&#xff0c;希望对大家有所帮助。 快速使用 netstat 命令&#xff08;推荐&#xff09; netstat 命令可以显示网络连接、路由表和网络接口信息等。可以使用 net…

股票量化分析工具QTYX使用攻略——代号“飞龙在天”,狙击龙头股战法(更新2.7.1)...

搭建自己的量化系统 股票量化交易系统QTYX是一个即可以用于学习&#xff0c;也可以用于实战炒股分析的系统。 分享QTYX系统目的是提供给大家一个搭建量化系统的模版&#xff0c;最终帮助大家搭建属于自己的系统。因此我们提供源码&#xff0c;可以根据自己的风格二次开发。 关于…

芯片学习记录LM2596

LM2596 芯片介绍 LM2596 系列稳压器是为降压开关稳压器提供所有有效 功能的单片集成电路&#xff0c; 能够驱动 3A 的负载 &#xff0c; 并且拥有 出色的线路和负载调节性能。这些器件可提供 3.3V 、 5V、 12V 固定输出电压和可调节输出电压版本。 这类稳压器不仅需要很少的…

企业如何通过媒体宣传扩大自身影响力

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 企业可以通过媒体宣传来扩大自身的影响力。可以通过以下的方法。 1. 制定媒体宣传战略&#xff1a; - 首先&#xff0c;制定一份清晰的媒体宣传战略&#xff0c;明确您的宣传目标、目标…

Ubuntu:Arduino IDE 开发环境配置【保姆级】

物联网开发学习笔记——目录索引 本章主要介绍在Ubuntu系统搭建Arduino IDE 开发环境&#xff0c;windows系统请移步&#xff1a;Windows&#xff1a;Arduino IDE 开发环境配置【保姆级】 参考官网&#xff1a;Arduino - Home 有关更多详细信息&#xff0c;请参阅 Arduino …

SpringCloud-Stream

一、介绍 &#xff08;1&#xff09;提供统一接口操作不同厂商的消息队列组件&#xff0c;降低学习成本 &#xff08;2&#xff09;生产者和消费者只需操作binder对象即可与消息队列交互&#xff0c;生产者output&#xff0c;消费者input &#xff08;3&#xff09;核心概念&a…