贪心算法(例题详细解说)

news2024/9/20 20:32:20

日升时奋斗,日落时自省 

目录

1、选择排序

2、分割平衡字符串 

3、买卖股票的最佳时机 II 

4、跳跃游戏

5、钱币找零

6、多机调度问题

 7、活动选择

8、无重复区间


贪心思想:顾名思义 贪 是该算法的一大特点,如何贪???

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

那使用什么情况?

(1)贪心算法针对所有问题的整体最优可以通过一系列局部最优的选择,即贪心选择来达到,这是贪心算法可行的第一个基本要素;

(2)当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质,运用贪心策略将每一次转化都取得最优解,每一次操作都能直接对结果产生影响

基本思路:从问题的某一初始解出发一步一步地进行,根据谋个优化测度,每一步都要确保能获得局部最优解。每一步值考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起了,就不再把数据填进部分解中,直接进行枚举,或者不再添加表示算法停止

实际上,贪心算法使用的情况比较少,再使用之前选择该问题下的几个实际数据进行分析,判断即可

算法这个问题仅仅拿文字叙述太过潦草了,通过以下可以用贪心算法试题来详细理解

1、选择排序

选择排序其实就是利用贪心算法进行的,每次找到一个最小值下标,将当前序列的最小值和当前序列的开始下标进行交换;每次排序都再影响结果,以为每次排序都涉及到当前序列的最小值,整个序列从开始位置逐渐偏向有序从小到大

 代码解析(附加注释解释):

    public static  void selectSort(int[] arr){
        //外部for循环就是指当前序列 从0下标开始的当前序列 等 i++后就是 就是从1下标开始的当前序列
        for(int i=0;i<arr.length;i++){ 
            int minindex=i;
            //从当前序列开始位置后找最小值  
            for(int j=i+1;j<arr.length;j++){
                if(arr[j]<arr[minindex]){
                    minindex=j;
                }
            }
            //找到当前序列的最小值之后就进行交换 当前序列的开始位置就已经确定了
            if(minindex!=i){
                swap(arr,minindex,i);
            }
        }
    }
    private static void swap(int[] arr, int minindex, int i) {
        int tmp=arr[minindex];
        arr[minindex]=arr[i];
        arr[i]=tmp;
    }

2、分割平衡字符串 

题目详细了解来源力扣 :  力扣  

其实题目大体解释就是:在一个平衡字符串中: L 和 R 字符数量上是相同的,将该字符串尽可能多的分割成平衡字符串

例如: 把 LRLLLRRR 分割下来就是 LR 和 LLLRRR 这两个  既有L也有R的字符串

注:最终问的最多能分成几个平衡字符串

思路: 
(1)既然说的是平衡 那就定义一个 量表示平衡 balance 表示
(2)balance什么时候最平衡 0 的时候最平衡 
(3)如果遇到了L balance ++  ,如果遇到了R balance --  一个加一个减如果平衡不就是0
(4)最后balance 处理完了, 进行判断balance当前是不是为0 也就是表示是不是一个平衡字符串

 代码解析(附加注释解释):

    public  int balancedStringSplit(String s){
        int count=0;   //用来计数的
        int balance=0;  //记录平衡
        for(int i=0;i<s.length();i++){
            //处理平衡字符串  
            if(s.charAt(i)=='L'){
                balance++;
            }else if(s.charAt(i)=='R'){
                balance--;
            }
            //平衡处理结束后 进行判定是否平衡
            //每经过一次判定一次 也就没有回退操作,贪心算法步步都响应一系列局部最优
            if(balance==0){
                //计数   当前这段平衡字符串 是平衡的 计数加一
                count++;
            }
        }
        return count;
    }

3、买卖股票的最佳时机 II 

题目详细了解来源力扣 : 力扣

 给定一个数组 ,它的第i 个元素 是一支给定股票 第i天的价格

设计一个算法来计算你所能获得的最大利润,你可以尽可能地完成更多的交易(可以多次买卖一支股票)

注:手里只能有一支股票 ,也就是你买了一支股票就需要先卖掉,才能,买下一支股票

 代码解析(附加注释):

    public static  int maxProfit(int[] prices){
        int result=0;  //用来记录当前利润收入
        //  当前手上有一支股票 所以 i从 1下标开始
        for(int i=1 ;i<prices.length;i++){
            //计算今天和明天股票的利润
            int curProfit=prices[i]-prices[i-1];
            //如果股票的利润是正数那就记录下来 贪心算法 每次买卖股票最优就是有利润
            if(curProfit>0){
                result+=curProfit;
            }
        }
        return result;
    }

4、跳跃游戏

题目详细了解来源力扣 :力扣

(1)给定一个非负整数数组,你最初位于数组的第一个位置

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

(3)判断你是否能够到达最后一个位置

 代码解析(附加注释解释):

    public boolean canJump(int[] nums){
        int n=nums.length;  //计算数组元素个数   用于判定跳跃是否能跳到
        int rightmost=0;    //此处是记录 跳跃最大能跳到右侧的哪里
        for(int i=0;i<nums.length;i++){
            //当前锁在最大值不能小于当前下标了, 否则说明最大值只能跳跃到当前下标或者跳跃不到当前位置
            if(i<=rightmost){
                //贪心判定 每次都是 只保留最大跳跃的位置
                rightmost=Math.max(rightmost,i+nums[i]);
                //直到第一个最大跳跃位置能当前数组最后的位置
                if(rightmost<=n-1){
                    return true;
                }
            }
        }
        return false;
    }

5、钱币找零

假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0, c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?
例如:将96转化为零钱 

贪心思想:

(1)从最大的币值开始 也就是 100币值 大于当前值 向后缩减

(2)进行下一个币值的比较如果小于当前值,将当前值最大处理(图片解释)

(3)最终判定96是否能全部被置换,如果不能返回NO 如果能返回最少几张钱币

代码解析(附加注释): 

    public static void main(String[] args) {
        //设置 以下面值以及对应的数量 
        int[][] moneyCount={{1,3},{2,1},{5,4},{10,3},{20,0},{50,1},{100,10}};
        //输入你要 置换的面值 
        Scanner scanner=new Scanner(System.in);
        int money;
        System.out.println("请输入要支付的钱");
        money=scanner.nextInt();
        //进行置换处理
        int result=solve(money,moneyCount);
        //判断如果返回值不是 -1 那说明能置换成功
        if(result!=-1){
            System.out.println(result);
        }else{
            System.out.println("No");
        }
    }
    private static int solve(int money, int[][] moneyCount) {
        int num=0;
        //贪心 思想
        //从面值大 钱币开始  为了能够以最少的钱币数量 置换结束
        for(int i=moneyCount.length-1;i>=0;i--){
            //求需要置换的钱 和 能中和掉多少张当前面值 取最小值
            //一个是 要满足 当前的钱 能 容纳下
            //另一个 要满足 面值数量 是否够
            int c=Math.min(money/moneyCount[i][0],moneyCount[i][1]);
            //将当前的钱 - 最大数量的面值
            money=money-c*moneyCount[i][0];
            //加上需要消耗的面值数量
            num+=c;
        }
        //如果不能找开 钱就还有剩余  所以返回-1 
        if(money>0){
            return -1 ;
        }
        //如果能找开, 返回钱币数量
        return num;
    }

6、多机调度问题

某工厂有n个独立的作业,由m台相同的机器进行加工处理,作业i所需的加工时间ti,任何作业在被处理时不能中断,也不能进行拆分处理。现厂长请你给写一个程序:算出n个作业由m台机器加工处理的最短时间

此处:贪心思维就在于处理最大任务时间,将任务时间从降序分配给时间任务最小的机器

题目解析:

(1)首先需要输入机器数 ,一台机器处理一个任务时间

(2)如果任务数大于机器数:就是将处理最短时间任务的机器,将其他任务时间给当前机器

(3)重复以上操作(以下图解)

 代码解析(附加注释):

以下代码有点长, 图解是思路解释,先通好思路,然后看以下代码,注释详细

public class MultiMachineTest {
    public static void main(String[] args) {
        int n,m;
        System.out.println("请输入作业数和机器数");
        Scanner scanner=new Scanner(System.in);
        //输入任务数量
        n=scanner.nextInt();
        //机器数量
        m=scanner.nextInt();
        //创建一个针对任务数量的数组 一会用于存放对应的任务的时间
        Integer[] works=new Integer[n];
        //以数组创建m个机器
        Integer[] machines=new Integer[m];
        //给每个任务都需要赋值一定的任务时间
        for(int i=0;i<n;i++){
            works[i]=scanner.nextInt();
        }
        //将所有机器处理
        System.out.println(greedStrateg(works,machines));
    }
    private static int greedStrateg(Integer[] works, Integer[] machines) {
        //首先 给定的时间肯定不是有序的 所以需要对当前传来数组进行排序 还是降序排序
        //贪心算法 从最大时间开始
        int minimaTime= machines.length; //记录最短时间
        int workNum=works.length; //机器数量
        Arrays.sort(works,new myComparator());
        //作业数如果小于机器数 ,直接返回最大的作业时间 其实也就是最短时间
        if(workNum<minimaTime){
            return works[0];
        }else{
            //作业数大于机器数的情况
            for(int i=0;i<works.length;i++){
                //选择最小的机器 任务时间加上
                int flag=0;
                //首先假设用第一个机器处理  ,也就是临时机器
                int tmp=machines[flag];
                //从剩余的机器中找运行时间最短的机器,进行加任下一个任务
                for(int j=1;j<machines.length;j++){
                    //找最小值 进行加任务  有点像插入排序
                    if(tmp>machines[j]){
                        flag=j;
                        //记录下来
                        tmp=machines[j]; 
                    }
                }
                //将当前作业交给最小的机器执行
                machines[flag]+=works[i];
            }
            //从所有机器中选出最后执行完成作业的机器   刚刚图解再最后找的是当前序列的最大值
            minimaTime=findMax(machines);
            return minimaTime;
        }
    }
    private static int findMax(Integer[] machines) {
        //先假设机器的 为最小值
        int ret=machines[0];
        //进行操作比对操作
        for(int cur:machines){
            //找到当前序列的最大值
            if(ret<cur){
                ret=cur;
            }
        }
        //返回最大值  也是所有机器运行的最短时间
        return ret;
    }
}
class myComparator implements Comparator<Integer> {
    @Override
    public int compare(Integer a, Integer b) {
        return b-a;
    }
    //按作业时间从大到小排序
}

 7、活动选择

有n个需要在同一天使用同一个教室的活动a1, a2, …, an,教室同一时刻只能由一个活动使用。每个活动a[i]都有一个开始时间s[i]和结束时间f[i]。一旦被选择后,活动a[i]就占据半开时间([s[i],f[i])。如果([s[i],f[i])和([s[j],f[j])互不重叠,a[i]和a[j]两个活动就可以被安排在这一天。求使得尽量多的活动能不冲突的举行的最大数量

 代码解析(附加注释):

public class ActivitySelection {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int number=scanner.nextInt();
        //活动 使用二维数组表示 行表示序号 列就表示0标 代表 开始时间和1标 代表 结束时间
        int[][] act=new int[number][2];
        int idx=0;
        for(int i=0;i<act.length;i++){
            act[i][0]=scanner.nextInt(); //表示开始时间
            act[i][1]= scanner.nextInt(); //表示结束时间
        }
        //以结束时间排序  贪心就在于找结束时间 主要就是找
        Arrays.sort(act,new MyComparator());
        //这就是 活动选择
        int ret=greedyActivitySelector(act);
        System.out.println(ret);
    }
    public static  int greedyActivitySelector(int[][] act){
        //num表示活动个数 本身就是1个 所以num=1 i表示当前活动
        int num=1,i=0;
        //j=1表示下一个活动
        for(int j=1;j<act.length;j++){
            //表示下一个活动开始时间 大于 当前活动结束时间
            if(act[j][0]>=act[i][1]){
                //进行比对成功后 下一个活动也成了当前活动
                i=j;
                //每能进行一次比对 活动个数加一
                num++;
            }
        }
        return num;
    }
}
class  MyComparator implements Comparator<int[]>{
    //以  活动结束时间   进行排序
    @Override
    public int compare(int[] o1, int[] o2) {
        return o1[1]-o2[1];
    }
}

8、无重复区间

题目详细了解来源力扣 :力扣

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠

注意:可以认为区间的终点总是大于它的起点,区间[1,2]和[2,3]的边界相互“接触”,但没有相互重叠

 代码解释(附加注释):

    class MyComparatorNow implements Comparator<int[]>{
        @Override
        public int compare(int[] o1, int[] o2) {
            //用来计算  前者排序
            return o1[0]-o2[0];
        }
    }
    public int eraseOverlapIntervals(int[][] intervals){
        if(intervals.length==0){
            return 0;
        }
        //此处进行排序 排序的是区间的开始位置  为以下的操作做准备
        Arrays.sort(intervals,new MyComparatorNow());
        int end=intervals[0][0];  //把当前位置作为准备的区间
        int prev=0;               //前一个区间
        int count=0;              //用来计数 要移除的区间
        for(int i=1;i<intervals.length;i++){
            //对比的是     前一个区间的末尾位置 大于 后一个区间的初识位置
            //第二种情况
            if(intervals[prev][1]>intervals[i][0]){
                //当前范围内是大于后一个区间的初识位置,还要判断是否大于后一个区间的末尾位置
                //前一个区间包含了后一个区间,那就说明了出现重复区间了
                //第三种情况
                if(intervals[prev][1]>intervals[i][1]){
                    //此处是包含后一个区间了 为了减少前一个大区间的影响,前一个大区间会被移除,留下后一个小区间
                    prev=i;
                }
                //当前无论是前一个区间还是后一个区间
                //因为第二种情况 包含了 第三种情况 都是要进行移除数量+1
                count++;
            }else{//第一种情况
                //如果 前一个区间的末尾值 小于 后一个区间的初始值
                //那就将下一个区间作为对比区间  当前不是重叠区间
                prev=i;
            }
        }
        //返回区间个数
        return count;
    }

 总结:贪心算法针对最多最少类问题,可以进行一系列局部最优后完成整体最优,如果实际上问题,个例问题过多不就成了全部枚举,贪心算法是尽可能一系列局部最优,个别枚举。

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

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

相关文章

2023-01-28 clickhouse-聚合函数的源码再梳理

笔者在源码笔记1之中分析过ClickHouse的聚合函数的实现&#xff0c;但是对于各个接口函数的实际如何共同工作的源码&#xff0c;回头看并没有那么明晰&#xff0c;主要原因是没有结合Aggregator的类来一起分析聚合函数的是如果工作起来的。所以决定重新再完成一篇聚合函数的源码…

梦熊杯-十二月月赛-白银组题解-A.自由

A. Problem A.自由&#xff08;freedom.cpp&#xff09; 内存限制&#xff1a;256 MiB 时间限制&#xff1a;1000 ms 标准输入输出 题目类型&#xff1a;传统 评测方式&#xff1a;文本比较 题目描述: 「蒙德」是「自由」的国度。 巴巴托斯认为&#xff0c;如果一个数的…

ch1_2 计算机的基本组成

计算机的基本组成 1. 冯 诺依曼计算机的特点 计算机由五大部件组成指令和数据 以同等地位 存于存储器&#xff0c; 可按地址寻访。指令和数据用二进制 表示指令由操作码 和 地址码 组成&#xff1b;存储程序&#xff1b;以运算器 为中心&#xff1b; 2. 硬件框图 存储器&am…

【Java集合】HashSet源码分析

目录 一、Set简介 二、HashSet简介 2.1 简介 2.2 HashSet继承关系 三、源码分析 3.1 成员属性 3.2 构造方法 3.3 添加元素 3.3.1 add()方法 3.3.2 addAll()方法 3.4 删除元素 3.4.1 remove()方法 3.4.2 removeAll()方法 3.5 查询元素 3.5.1 contains()方法 3.5.2 containsAll方…

项目管理:如何编写高质量的Makefile?

文章目录背景熟练掌握 Makefile 语法规划 Makefile 要实现的功能设计合理的 Makefile 结构掌握 Makefile 编写技巧技巧 1&#xff1a;善用通配符和自动变量技巧 2&#xff1a;善用函数技巧 3&#xff1a;依赖需要用到的工具技巧 4&#xff1a;把常用功能放在 /Makefile 中&…

nodeJS - 切换使用淘宝镜像【临时切换、 长期切换】

一、文章引导 #mermaid-svg-zWQadgqvTsLhAes4 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-zWQadgqvTsLhAes4 .error-icon{fill:#552222;}#mermaid-svg-zWQadgqvTsLhAes4 .error-text{fill:#552222;stroke:#55222…

自动驾驶感知——视觉感知经典算法

文章目录1. 车道线检测技术1.1 基于规则的车道线检测技术1.1.1 流程框架1.1.2 预处理模块1.1.3 车道线识别感兴趣区域提取1.1.4 灰度图转化1.1.5 灰度图去噪1.1.6 二值化操作1.1.7 鲁棒性参数估计——RANSAC1.1.8 后处理模块1.1.9 输出1.2 车道线检测技术发展路线2. 目标检测技…

10.图和树基础

一、基本介绍 1.图 图描述的是一些个体之间的关系。这些个体之间既不是前驱后继的顺序关系&#xff0c;也不是祖先后代的层次关系&#xff0c;而是错综复杂的网状关系。我们一般用图G(V,E)G(V,E)G(V,E)来表示&#xff0c;VVV表示结点&#xff0c;EEE表示边。 根据边是否有权值…

爱快软路由安装Docker插件

在爱快云 插件应用中开启Docker插件 在爱快web端页面的[系统设置]->[磁盘管理]->[磁盘分区]设置磁盘分区&#xff0c;选择普通存储&#xff0c;挂载路径名可以随便取。 点击[高级应用]->[插件管理] 点击页面的Docker图标。 启用Docker服务 点击中间的[镜像管理]&…

n皇后问题

n皇后问题 题目&#xff1a; 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行 或同一列 或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的…

基于java的大理旅游系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

professional issue复习

Legal concepts Development of UK law • The Kingdom of England was established in 927. • The Principality of Wales was established in 1216. Common law • Following 1066, a unified system of law (English common law) slowly came into existence. It was “c…

漫谈cgroup

什么是cgroup cgroup 是linux内核的一个功能&#xff0c;用来限制、控制与分离一个进程组的资源&#xff08;如CPU、内存、磁盘I/O等&#xff09;。它是由 Google 的两位工程师进行开发的&#xff0c;自 2008 年 1 月正式发布的 Linux 内核 v2.6.24 开始提供此能力。 cgroup …

代码随想录算法训练营第30天 二叉树 java :39. 组合总和 40.组合总和II 131.分割回文串

文章目录LeetCode 39. 组合总和本题题解思路LeetCode 40.组合总和II本题题解思路LeetCode 131.分割回文串本题题解思路那么在代码里什么是切割线呢&#xff1f;那么在代码里什么是切割线呢&#xff1f;总结LeetCode 39. 组合总和 本题题解 思路 根据递归三部曲来分析 递归函…

单板硬件设计:存储器

在单板设计中&#xff0c;无论是涉及到一个简易的CPU、MCU小系统或者是复杂的单板设计&#xff0c;都离不开存储器设计&#xff1a; 1、存储器介绍 存储器的分类大致可以划分如下&#xff1a; ROM和RAM指的都是半导体存储器&#xff0c;ROM在系统停止供电的时候仍然可以保持…

visudo配置sudo权限

visudo配置sudo权限配置visudo仅允许字符终端登陆(tty)--授权localhost允许图形和tty登陆--授权all用户组提权-示例配置在sudoers.d目录下创建授权文件--推荐五段式配置三段式配置检查sudoers配置是否有误如何在sudo运行的命令中防止使用参数结果验证配置visudo https://blog.…

【数据结构】8.2 插入排序

文章目录前言1. 直接插入排序直接插入排序算法直接插入排序性能分析2. 折半插入排序3. 希尔排序希尔排序算法希尔排序算法分析排序方法比较前言 类似于俺们打牌时的插入&#xff0c;每抓来一张牌的时候&#xff0c;就将它放在合适的位置上&#xff0c;插入一张牌之后手里的牌仍…

MQ相关概念

1) 队列管理器 队列管理器是MQ系统中最上层的一个概念&#xff0c;由它为我们提供基于队列的消息服务。 2) 消息 在MQ中&#xff0c;我们把应用程序交由MQ传输的数据定义为消息&#xff0c;我们可以定义消息的内容并对消息进行广义的理解&#xff0c;比如&#xff1a;用户的各种…

JavaWeb-FilterListener

JavaWeb-Filter&Listener 1&#xff0c;Filter 1.1 Filter概述 Filter 表示过滤器&#xff0c;是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。 过滤器可以把对资源的请求拦截下来&#xff0c;从而实现一些特殊的功能。 如下图所示&#xff0c;浏览器可以访问服…

JAVA性能统计项目

一、项目背景&#xff1a;我们希望设计开发一个小的框架&#xff0c;能够获取接口调用的各种统计信息&#xff0c;比如&#xff0c;响应时间的最大值&#xff08;max&#xff09;、最小值&#xff08;min&#xff09;、平均值&#xff08;avg&#xff09;、百分位值&#xff08…