Java 贪心算法经典问题解决

news2024/12/24 9:26:05

文章目录

    • 分金条
      • 题目
      • 思路
      • 代码实现
      • 测试用例以及结果输出
    • 花费资金做项目最大收益
      • 题目
      • 思路
      • 代码实现
      • 测试用例以及结果输出
    • 预定会议室
      • 题目
      • 思路
      • 代码实现
      • 测试用例以及结果输出
    • 取中位数
      • 题目
      • 思路
      • 代码实现
      • 测试用例以及结果输出
    • 最低字典序
      • 题目
      • 思路
      • 代码实现
      • 测试用例以及结果输出
    • 结语

分金条

题目

一块金条切成两半,是需要花费和长度数值一样的铜板的。比如 长度为20的 金条,不管切成长度多大的两半,都要花费20个铜 板。一群人想整分整块金 条,怎么分最省铜板?

例如,给定数组{10,20,30},代表一共三个人,整块金条长度为 10+20+30=60. 金条要分成10,20,30三个部分。 如果, 先把长 度60的金条分成10和50,花费60 再把长度50的金条分成20和30, 花费50 一共花费110铜板。 但是如果, 先把长度60的金条分成30和30,花费60 再把长度30 金条分成10和20,花费30 一共花费90铜板。

输入一个数组,返回分割的最小代价。

思路

哈夫曼树带权路径计算问题,更多了解可参考:哈夫曼树及其应用

  1. 先将给定数组进行排序,这里可以使用优先级队列处理【优先级堆结构】,将数组依次丢入优先级队列中;
  2. 每次从优先级队列中取出较小的值相加,记录计算结果,同时将结果重新丢入到队列中,直到队列中没有元素;
  3. 将过程中的所有计算结果相加,结果即为分割最小代价;

代码实现

   private static int lessMoney(int[] aar) {
        PriorityQueue<Integer> pQ = new PriorityQueue<>();
        for (int i = 0; i < aar.length; i++) {
            pQ.add(aar[i]);
        }
        int result = 0;
        int cur = 0;
        while (pQ.size() > 1) {
            cur = pQ.poll() + pQ.poll();
            result += cur;
            pQ.add(result);
        }
        return result;
    }

测试用例以及结果输出

  public static void main(String[] args) {
        int[] aar = new int[]{30, 10, 20};
        System.out.println(lessMoney(aar));
    }

输出结果:

90

花费资金做项目最大收益

题目

输入:
参数1,正数数组costs
参数2,正数数组profits
参数3, 正数k
参数4,正数m

其中,costs[i]表示i号项目的花费;profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润);
k表示你不能并行、只能串行的最多做k个项目;
m表示你初始的资金;
说明:你每做完一个项目,马上获得的收益,可以支持你去做下一个 项目。
输出:你最后获得的最大钱数。

思路

基本原则:结合生活中的实际生产,每次选花费最小收益最高的项目去做,最终得到的收益肯定是最大的;

  1. 新定义Node类,包含每个项目对应的花费以及收益;
  2. 分别定义两个优先级队列,按照最小花费和最大收益优先级取元素;
  3. 将根据花费以及收益数组生成的Node数组丢入到最小花费优先级队列中;
  4. 进行K次遍历【最多可以做K个项目】,不断从最小花费优先级队列中取出项目,丢入到最大收益优先级队列中【注意资金问题】,在根据最大收益去做项目【即从最大收益队列中取项目做】,计算过程中获取的收益之和;

代码实现

/**
     * 计算最大收益
     *
     * @param k       表示能做K个项目
     * @param m       表示启动资金
     * @param profits 表示做每个项目去除花费后的利润
     * @param costs   表示做每个项目对应的花费
     * @return
     */
    private static int getMaxProfit(int k, int m, int[] profits, int[] costs) {
        //将项目对应花费以及收益包装成Node类,添加到Node[]数组中
        Node[] nodes = new Node[costs.length];
        for (int i = 0; i < costs.length; i++) {
            nodes[i] = new Node(costs[i], profits[i]);
        }
        // 最小花费优先级队列
        PriorityQueue<Node> minConstQ = new PriorityQueue<>(new MinComparator());
        // 最大收益优先级队列
        PriorityQueue<Node> maxProfitQ = new PriorityQueue<>(new MaxComparator());
        //添加到最小花费优先级队列中
        for (int i = 0; i < nodes.length; i++) {
            minConstQ.add(nodes[i]);
        }
        // k表示最多可以做k个项目
        for (int i = 0; i < k; i++) {
            //只要花费不超过启动资金,按照最小花费不断从队列中取,丢入到收益队列中
            while (!minConstQ.isEmpty() && minConstQ.peek().cost <= m) {
                maxProfitQ.add(minConstQ.poll());
            }
            //如果收益队列为空,就返回最终资金,否则每次从收益队列中取最大收益的项目去做;
            if (maxProfitQ.isEmpty()) {
                return m;
            }
            m = m + maxProfitQ.poll().profit;
        }
        return m;
    }

    private static class Node {
        /**
         * 花费
         */
        public int cost;
        /**
         * 利润
         */
        public int profit;

        public Node(int cost, int profit) {
            this.cost = cost;
            this.profit = profit;
        }
    }


    /**
     * 花费最小排序
     */
    private static class MinComparator implements Comparator<Node> {

        @Override
        public int compare(Node o1, Node o2) {
            return o1.cost - o2.cost; //>0表示o1>o2
        }
    }

    /**
     * 利润最大排序
     */
    private static class MaxComparator implements Comparator<Node> {

        @Override
        public int compare(Node o1, Node o2) {
            return o2.profit - o1.profit; // >0 表示o2>o1
        }
    }

测试用例以及结果输出

   public static void main(String[] args) {
        int k = 3;
        int m = 5;
        int[] profits = new int[]{1, 3, 4, 6, 8};
        int[] costs = new int[]{3, 6, 4, 2, 6};
        System.out.println(getMaxProfit(k, m, profits, costs));
    }

输出结果:

23

预定会议室

题目

一些项目要占用一个会议室宣讲,会议室不能同时容纳两个项目的宣讲。

给你每一个项目开始的时间和结束的时间(给你一个数组,里面是一个个具体的项目),你来安排宣讲的日程,

要求会议室进行的宣讲的场次最多,返回这个最多的宣讲场次。

思路

优先做最早结束的项目,保证开始时间小于或等于要做项目的开始时间即可;

代码实现

 private static int getMaxProgram(Program[] program, int start) {
        Arrays.sort(program, new ProgramComparator());
        int result = 0;
        for (int i = 0; i < program.length; i++) {
            if (start <= program[i].start) {
                result++;
                start = program[i].end;
            }
        }
        return result;
    }

    /**
     * 定义项目会议  包含开始和结束时间
     */
    private static class Program {
        public int start;
        public int end;

        public Program(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }

    /**
     * 按哪个项目先结束排序
     */
    private static class ProgramComparator implements Comparator<Program> {
        @Override
        public int compare(Program o1, Program o2) {
            return o1.end - o2.end;
        }
    }

测试用例以及结果输出

    public static void main(String[] args) {
        Program p1 = new Program(6, 10);
        Program p2 = new Program(7, 8);
        Program p3 = new Program(11, 13);
        Program p4 = new Program(13, 15);
        Program[] programs = new Program[]{p1, p2, p3, p4};
        System.out.println(getMaxProgram(programs, 6));
    }

输出结果:

3

取中位数

题目

一个数据流中,随时可以取得中位数;

思路

分别定义大根堆和小根堆,以下述逻辑进行存放和调整;

  1. 当大根堆为空时,元素直接添加到大根堆中;
  2. 当大根堆不为空时,如果元素小于或等于大根堆堆顶元素,则添加到大根堆中,否则添加到小根堆中;
  3. 当大根堆和小根堆元素个数相差为2时,需要进行堆调整,将元素个数多的堆堆顶元素放入元素个数少的堆中;
  4. 计算中位数,当大根堆和小根堆元素个数相等,则中位数为取两个堆的堆顶元素之和除以2,如果元素个数不相等,则中位数为元素个数多的堆的堆顶元素;

下面以以图进行举例说明,这里简单以队列表示大小根堆:

中位数计算
可以理解成通过堆对元素进行排序,只不过利用大小根队的性质,保证中位数可以通过堆顶数据进行计算得出,也避免了每次添加元素时进行排序问题,时间复杂度更低;

代码实现

    private static class MedianHelper {
        private PriorityQueue<Integer> minQ = new PriorityQueue<>(new MinComparator());
        private PriorityQueue<Integer> maxQ = new PriorityQueue<>(new MaxComparator());


        public int getMedian() {
            int maxQSize = maxQ.size();
            int minQSize = minQ.size();
            if (maxQSize == 0) {
                return 0;
            }
            //元素个数相等,取两者堆顶元素/2
            if (maxQSize == minQSize) {
                return (maxQ.peek() + minQ.peek()) / 2;
            }
            //元素个数不相等,取元素多的堆顶元素
            return maxQSize > minQSize ? maxQ.peek() : minQ.peek();
        }

		//插入元素
        public void addNum(int num) {
            if (maxQ.isEmpty()) {
                maxQ.add(num);
            } else {
                if (maxQ.peek() >= num) {
                    maxQ.add(num);
                } else {
                    minQ.add(num);
                }
            }
            modifyQSize();
        }


        /**
         * 调整两个堆的大小 一旦发现两个堆数据个数相差为2,则取多的丢到少的里面
         */
        private void modifyQSize() {
            int minQSize = minQ.size();
            int maxQSize = maxQ.size();
            if (minQSize - maxQSize == 2) {
                maxQ.add(minQ.poll());
            }
            if (maxQSize - minQSize == 2) {
                minQ.add(maxQ.poll());
            }
        }
    }

测试用例以及结果输出

    public static void main(String[] args) {
        int[] aar = new int[]{8, 6, 13, 10, 11, 19};
        MedianHelper helper = new MedianHelper();
        for (int i : aar) {
            helper.addNum(i);
        }
        System.out.println(helper.getMedian());

    }

输出结果:

10

最低字典序

题目

给定一个字符串类型的数组strs,找到一种拼接方式,使得把所有字符串拼起来之后形成的字符串具有最低的字典序。

思路

保证每次拼接后的字符串都是最低字典序的即可;

代码实现

 private static String lowestString(String[] strs) {
        if (strs == null || strs.length == 0) {
            return "";
        }
        Arrays.sort(strs, new LowestComparator());
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < strs.length; i++) {
            result.append(strs[i]);
        }
        return result.toString();
    }


    /**
     * 定义两个字符拼接最小字典序比较器
     */
    private static class LowestComparator implements Comparator<String> {

        @Override
        public int compare(String o1, String o2) {
            return (o1 + o2).compareTo(o2 + o1);
        }
    }

测试用例以及结果输出

    public static void main(String[] args) {
        String[] strs2 = {"b", "ab", "ac"};
        System.out.println(lowestString(strs2));
    }

结果输出:

abacb

结语

如果以上文章对您有一点点帮助,希望您不要吝啬的点个赞加个关注,您每一次小小的举动都是我坚持写作的不懈动力!ღ( ´・ᴗ・` )

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

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

相关文章

如何在工作中利用Prompt高效使用ChatGPT

导读 AI 不是来替代你的&#xff0c;是来帮助你更好工作。用better prompt使用chatgpt&#xff0c;替换搜索引擎&#xff0c;让你了解如何在工作中利用Prompt高效使用ChatGPT。 01背景 现在 GPT 已经开启了人工智能狂潮&#xff0c;不过是IT圈&#xff0c;还是金融圈。 一开…

【线性规划、非线性规划、多目标规划】

有限的条件下&#xff0c;最大的收益 线性规划就是在一组线性约束条件下&#xff0c;求线性目标函数的最大或者最小值 线性就是指所有的变量都是一次方 整数规划、0-1规划都是默认为线性规划的特例 MATLAB自带的函数求解线性规划问题&#xff1a; Linprog函数 模型化为MATL…

docker+Jenkins

拉取镜像 docker pull jenkins/jenkins启动容器 8080端口映射58080 jenkins_home 映射本地/data/下方便查看 docker run -d -p 58080:8080 -p 5000:50000 -v /data/jenkins_home:/var/jenkins_home -v /etc/localtime:/etc/localtime --name jenkins jenkins/jenkins访问ip:5…

线性神经网路——线性回归随笔【深度学习】【PyTorch】【d2l】

文章目录 3.1、线性回归3.1.1、PyTorch 从零实现线性回归3.1.2、简单实现线性回归 3.1、线性回归 线性回归是显式解&#xff0c;深度学习中绝大多数遇到的都是隐式解。 3.1.1、PyTorch 从零实现线性回归 %matplotlib inline import random import torch #d2l库中的torch模块&a…

前端密码加密 —— bcrypt、MD5、SHA-256、盐

&#x1f414; 前期回顾悄悄告诉你&#xff1a;前端如何获取本机IP&#xff0c;轻松一步开启网络探秘之旅_彩色之外的博客-CSDN博客前端获取 本机 IP 教程https://blog.csdn.net/m0_57904695/article/details/131855907?spm1001.2014.3001.5501 在前端密码加密方案中&#xff…

开发一个RISC-V上的操作系统(三)—— 串口驱动程序(UART)

目录 文章传送门 一、什么是串口 二、本项目串口的FPGA实现 三、串口驱动程序的编写 四、上板测试 文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&…

Linux-定时清除日志No space left on device

由于开发环境上一般机器资源较少&#xff0c;很容易导致因日志文件过大而导致系统宕机&#xff0c;报错No space left on device等问题&#xff0c;我们可以通过添加定时任务&#xff0c;自动删除日志从而达到节省空间的目的 操作步骤&#xff1a; 云服务器进入救援模式(若服…

目前主流的几个Web前端框架

启动项目时&#xff0c;请查看 2023 年最好的 Web 前端框架。为什么选择合适的工具很重要? 前端开发人员使用前端框架来简化工作。这些软件包通常提供可重用的代码模块、系统化的前端技术和预构建的接口块。这使团队可以更快、更轻松地创建可持续的 Web 应用程序和用户界面&am…

[linux]VI编辑器常用命令

VI编辑器常用命令 命令用法含义dd删除游标所在一整行d1G删除光标所在到第一行的所有数据dG删除光标所在到最后一行的所有数据d$删除光标所在处&#xff0c;到该行的最后一个字符d0那个是数字0,删除光标所在到该行的最前面的一个字符x,Xx向后删除一个字符(相当于[del]按键),X向…

深入浅出多种开发语言对接淘宝京东1688阿里巴巴等电商平台,获取实时商品详情数据API接口介绍

api接口详解大全?优秀的设计是产品变得卓越的原因设计API意味着提供有效的接口&#xff0c;可以帮助API使用者更好地了解、使用和集成&#xff0c;同时帮助人们有效地维护它每个产品都需要使用手册&#xff0c;API也不例外在API领域&#xff0c;可以将设计视为服务器和客户端之…

Oracle中varchar2、clob字段类型中特殊字符会显示为问号解决方法

项目中遇到varchar2、clob字段存储数据&#xff0c;内容中存在特殊字符导致显示问号&#xff0c;以下说明解决此问题的办法 首先我们查询下数据库编码、客户端编码、查询用户操作系统字符集 --查看oracle数据库编码 select * from nls_database_parameters where parameter NL…

MySQL数据库第十一课---------SQl语句的拔高-------水平提升

作者前言 个人主页::小小页面 gitee页面:秦大大 一个爱分享的小博主 欢迎小可爱们前来借鉴 ______________________________________________________ 目录 SQL提高 日期函数 length round reverse substring ifnull case when cast grouping sets 排序函数 开窗函…

从零到一,激活GPU的力量:使用TensorRT量化和CUDA并行编程

TensorRT学习笔记 前情提要&#xff1a;TensorRT 模型优化与推理&#xff1a;从零到一&#xff0c;激活GPU的力量&#xff1a;使用TensorRT优化和执行深度学习模型&#xff0c;你的TensorRT入门指南 本篇将会介绍TensorRT下的模型量化与CUDA并行计算编程的介绍。 TensorRT模型…

【雕爷学编程】Arduino动手做(170)---LGT8F328P 开发板

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

如何在3ds max中创建可用于真人场景的巨型机器人:第 2 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 创建主体 步骤 1 打开 3ds Max。选择机器人头部后&#xff0c;二次单击鼠标并选择隐藏未选中。机器人的其他部分 除了头部之外&#xff0c;将被隐藏。 打开 3ds Max 步骤 2 在人脸选择模式下&#x…

自动化测试项目实战

目录 1.熟悉项目 2.针对核心流程设计手工测试用例 3.手工测试用例转换为自动化测试用例 前置工作 测试工作 登陆界面 博客列表页数量 博客详情页检验 写博客并发布 校验标题&#xff0c;时间 删除博客 注销博客 针对博客系统进行自动化测试 1.熟悉项目 2.针对核…

2023年9月北京/广州/深圳CDGA/CDGP认证考试报名开启

据DAMA中国官方网站消息&#xff0c;2023年度第三期DAMA中国CDGA和CDGP认证考试定于2023年9月23日举行。 报名通道现已开启&#xff0c;相关事宜通知如下&#xff1a; 考试科目: 数据治理工程师(CertifiedDataGovernanceAssociate,CDGA) 数据治理专家(CertifiedDataGovernanc…

AlSD 系列智能安全配电装置是安科瑞电气有限公司专门为低压配电侧开发的一款智能安全用电产 品-安科瑞黄安南

一、应用背景 电力作为一种清洁能源&#xff0c;给人们带来了舒适、便捷的电气化生活。与此同时&#xff0c;由于使用不当&#xff0c;维护 不及时等原因引发的漏电触电和电气火灾事故&#xff0c;也给人们的生命和财产带来了巨大的威胁和损失。 为了防止低压配电系统发生漏…

数据结构和算法——表排序(算法概述、物理排序、复杂度分析,包含详细清晰图示过程)

目录 算法概述 物理排序 复杂度分析 算法概述 表排序用于 待排元素都为一个庞大的结构&#xff0c;而不是一个简单的数字&#xff0c;例如&#xff1a;一本书&#xff0c;一部电影等等。 如果这些待排元素都用之前的排序方法&#xff0c;元素需要频繁互换&#xff0c;那么…

uniapp 即时通讯开发流程详解

今天我将为您详细介绍UniApp开发中的即时通讯流程。本文将向您展示如何在UniApp中实现即时通讯功能&#xff0c;为您的应用程序增添交互性和实时性。 1. 准备工作 在开始开发之前&#xff0c;确保您已完成以下准备工作&#xff1a; 确保您已经安装好UniApp开发环境&#xff…