第十五节:贪心算法(下)

一 、 贪心算法的解题套路实战一(最多的会议宣讲场次)

1.1 描述

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

给你每一个项目开始的时间和结束的时间

你来安排宣讲的日程,要求会议室进行的宣讲的场次最多。

返回最多的宣讲场次。

1.2 分析 在绝对环境下选择最优解

贪心 先按会议结束时间排序,然后在在数组里面找,先以前开始时间为0,找第一个会议可以结束的时间更新会议下一个可以开始的时间为当前这个会议的结束时间,那么下一个会议可以开始的时间要大于前面那个结束的时间

1.3 代码

// 会议的开始时间和结束时间,都是数值,不会 < 0
    public static int bestArrange2(Program[] programs) {
        Arrays.sort(programs, new ProgramComparator());
        int timeLine = 0;//会议的默认结束时间
        int result = 0;
        // 依次遍历每一个会议,结束时间早的会议先遍历
                //比如上一个会议的结束时间比下一个会议的开始时间小,那么下一个会议就可以在上一个会议结束的时候开始
        for (int i = 0; i < programs.length; i++) {
            if (timeLine <= programs[i].start) {
                result++;
                timeLine = programs[i].end;
            }
        }
        return result;
    }
//比较器
    public static class ProgramComparator implements Comparator<Program> {

        @Override
        public int compare(Program o1, Program o2) {
            return o1.end - o2.end;
        }

    }

二 、 贪心算法的解题套路实战二(分割的最小代价)

2.1 描述

一块金条切成两半,是需要花费和长度数值一样的铜板的。

比如长度为20的金条,不管怎么切,都要花费20个铜板。 一群人想整分整块金条,怎么分最省铜板?

例如,给定数组{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铜板。

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

2.2 分析

贪心算法解决输入一个数组返回金条分割的最小代价既哈夫曼树

分析

根据上面的列子可以看出,切的时候尽可能的向平均靠近,之后的切的代价就越小

流程 使用小跟堆,每次从堆里面弹出两个树合完放入小根堆,等堆排好序后又弹出两个树,当小跟堆里面只剩一个树的时候停止,形成如下的树的方案就是最优方案,代价就是圈里面的值加起来-这就是在创建一棵哈夫曼树!

2.3 代码


    public static int lessMoney2(int[] arr) {
        PriorityQueue<Integer> pQ = new PriorityQueue<>();
        for (int i = 0; i < arr.length; i++) {
            pQ.add(arr[i]);
        }
        int sum = 0;
        int cur = 0;
        while (pQ.size() > 1) {
            cur = pQ.poll() + pQ.poll();
            sum += cur;
            pQ.add(cur);
        }
        return sum;
    }

三  贪心算法的解题套路三 (根据下面的描述你最后获得的最大钱数)

3.1 描述

输入: 正数数组costs、正数数组profits、正数K、正数M

costs[i]表示i号项目的花费

profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润)

K表示你只能串行的最多做k个项目

M表示你初始的资金

说明: 每做完一个项目,马上获得的收益,可以支持你去做下一个项目。只能窜行的做项目,不能并行的做项目。

输出:你最后获得的最大钱数。
 

3.2 分析

第一步 第一轮

分析先把所有数据按照花费放到小根堆里面,然后再来一个大根堆,按照利润来组织;假如我的钱是2元,小根堆里面所有能做的项目弹出来进大根堆;(1,3)(2,5)弹出进大根堆在大根堆里面是(2,5)(1,3)这个时候做要做的项目就是大根堆的堆顶;这个时候的利润就是2(本金)+5(利润)=7,

第二轮来了,接着第一轮的过程,从小根堆里面弹出7元能做的项目到大根堆里面;

第二轮

根据钱数去解锁小根堆,到大根堆做堆顶的树,一直循环

3.3 代码

package class14;

import java.util.Comparator;
import java.util.PriorityQueue;

public class Code04_IPO {

    // 最多K个项目
    // W是初始资金
    // Profits[] Capital[] 一定等长
    // 返回最终最大的资金
    public static int findMaximizedCapital(int K, int W, int[] Profits, int[] Capital) {
        PriorityQueue<Program> minCostQ = new PriorityQueue<>(new MinCostComparator());
        PriorityQueue<Program> maxProfitQ = new PriorityQueue<>(new MaxProfitComparator());
        for (int i = 0; i < Profits.length; i++) {
            minCostQ.add(new Program(Profits[i], Capital[i]));
        }
        for (int i = 0; i < K; i++) {
            while (!minCostQ.isEmpty() && minCostQ.peek().c <= W) {
                maxProfitQ.add(minCostQ.poll());
            }
            if (maxProfitQ.isEmpty()) {
                return W;
            }
            W += maxProfitQ.poll().p;
        }
        return W;
    }

    public static class Program {
        public int p;
        public int c;

        public Program(int p, int c) {
            this.p = p;
            this.c = c;
        }
    }

    public static class MinCostComparator implements Comparator<Program> {

        @Override
        public int compare(Program o1, Program o2) {
            return o1.c - o2.c;
        }

    }

    public static class MaxProfitComparator implements Comparator<Program> {

        @Override
        public int compare(Program o1, Program o2) {
            return o2.p - o1.p;
        }

    }

}

四 墙 路问题,需要多少灯

4.1 描述

给定一个字符串str,只由‘X’和‘.’两种字符构成。

‘X’表示墙,不能放灯,也不需要点亮

‘.’表示居民点,可以放灯,需要点亮

如果灯放在i位置,可以让i-1,i和i+1三个位置被点亮

返回如果点亮str中所有需要点亮的位置,至少需要几盏灯

4.1 分析 当前轮次对i的几种情况的处理

4.2 代码

五 并查集((并)又可以合并 (查)即可查找)

5.1 描述

如下先将自己设置成一个单独的集合,查找两个小样本是否全在一个大点的集合叫并查集,其实很多设计是可以做到这个功能的

比如 list

但是有100万个数的情况,需要将a的100万个合到b里面去,要倒100万次

所以有了以下的设计,并查集单独讲主要是他的性能非常的优异

开始的时候找一个指针指向自己,假如我们要找 a所在的集合a,e所在的集合是不是在一个集合,我怎么给你查,一开始肯定都不是,

那怎么查,a往上找找到不能再往上的节点是a,e往上找找到不能再往上的节点是e,我们把一个节点往上找,找到不能再往上的那个节点叫节点的代表节点,如下所是 a的代表节点是a,b的代表节点是b

下面我们要求a和e所在的集合给合并起来,同样找代表节点, a的代表节点是a,b的代表节点是b,建立一种机制,a所在的集合大小1,e的集合大小也是1,怎么变成一个结合,直接让e的指针往a上指,以后再找a和e是否是一个集合, a往上找不能再找了是a,e往上找不能再找了也是a

接着再玩,找e和c是不是一个集合,同样找e和c的代表集点,e是a,c是c,不在一个结合,怎么合并,此时a所在的集合大小是2,c所在的结合大小是1,这个时候怎么合并谁挂谁,小的去挂大的,e挂在a下,这个时候a,e,c的代节点都是a

5.2 分析

核心是我是拿代表节点属于那个集合

优化一

小挂大

优化二

HashMap替代指针

首先我们是可以通过a找到f的,但是我们返回之前做一个优化 让当前链上的节点变为扁平,下一次再查的时候一步到位

public HashMapV>, NodeV>> parents; 如下

while (!path.isEmpty()) {

parents.put(path.pop(), cur);

}

优化三

public HashMapV>, Integer> sizeMap;的含义 只有集合的代表节点才会在sizeMap里面留下记录

5.3 代码

public class Code05_UnionFind {

    public static class Node<V> {
        V value;

        public Node(V v) {
            value = v;
        }
    }

    public static class UnionFind<V> {
        public HashMap<V, Node<V>> nodes;
        public HashMap<Node<V>, Node<V>> parents;
        public HashMap<Node<V>, Integer> sizeMap;

        public UnionFind(List<V> values) {
            nodes = new HashMap<>();
            parents = new HashMap<>();
            sizeMap = new HashMap<>();
            for (V cur : values) {
                Node<V> node = new Node<>(cur);
                nodes.put(cur, node);
                parents.put(node, node);
                sizeMap.put(node, 1);
            }
        }

        // 给你一个节点,请你往上到不能再往上,把代表返回
        public Node<V> findFather(Node<V> cur) {
         //    栈
            Stack<Node<V>> path = new Stack<>();
            //最开始的时候是将自己设置为自己的parents node,所以这里这样判断
            while (cur != parents.get(cur)) {
                path.push(cur);
                cur = parents.get(cur);
            }
                //优化1
            while (!path.isEmpty()) {
                parents.put(path.pop(), cur);
            }
            return cur;
        }

        public boolean isSameSet(V a, V b) {
            return findFather(nodes.get(a)) == findFather(nodes.get(b));
        }

        public void union(V a, V b) {
      //优化2
            Node<V> aHead = findFather(nodes.get(a));
            Node<V> bHead = findFather(nodes.get(b));
            if (aHead != bHead) {
                int aSetSize = sizeMap.get(aHead);
                int bSetSize = sizeMap.get(bHead);
                Node<V> big = aSetSize >= bSetSize ? aHead : bHead;
                Node<V> small = big == aHead ? bHead : aHead;
                parents.put(small, big);
                sizeMap.put(big, aSetSize + bSetSize);
    //优化三
                sizeMap.remove(small);
            }
        }

        public int sets() {
            return sizeMap.size();
        }

    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android 几种系统升级方式详解

目录 ◆ 概述 ● 几种启动模式 ● MISC分区 ● CACHE分区 ● 几种系统升级方式 ◆ Recovery升级 ● 升级包构成&#xff0c;签名&#xff0c;制作 ● 升级脚本 ● 升级过程 ◆ OTA升级 ● 升级包构成&#xff0c;制作 ● 升级脚本 ● 升级过程 ◆ fastboot升级 ◆ ADB升级 几…

System V IPC(进程间通信)机制详解

文章目录 一、引言二、System V IPC的基本概念1、IPC结构的引入2、IPC标识符&#xff08;IPC ID&#xff09;3、S ystem V的优缺点 三、共享内存&#xff08;Shared Memory&#xff09;1、共享内存的基本概念2、共享内存的创建&#xff08;shmget&#xff09;3、共享内存的附加…

FreeRTOS【4】线程挂起和恢复

1.开发背景 基于上一篇指引&#xff0c;成功创建并启动线程后&#xff0c;线程已经开始运行了&#xff0c;但是有时我们需要线程暂停运行&#xff0c;例如某个线程是控制 LED 闪灯的&#xff0c;如果现在需要让 LED 停止工作&#xff0c;单纯的关闭 LED 是没用的&#xff0c;因…

刷题之最长连续序列

哈希表 class Solution { public:int longestConsecutive(vector<int>& nums) {//set记录并且去重nums中的数unordered_set<int>set;for(int i0;i<nums.size();i){set.insert(nums[i]);}int result0;//遍历所有数for(auto iset.begin();i!set.end();i){//如…

智能EDM邮件群发工具哪个好?

企业之间的竞争日益激烈&#xff0c;如何高效、精准地触达目标客户&#xff0c;成为每个市场战略家必须面对的挑战。在此背景下&#xff0c;云衔科技凭借其前沿的AI技术和深厚的行业洞察&#xff0c;匠心推出了全方位一站式智能EDM邮件营销服务平台&#xff0c;重新定义了邮件营…

(三)Spring教程——依赖注入与控制反转

Spring框架是为了简化企业级应用开发而创建的&#xff0c;其强大之处在于对Java SE和Java EE开发进行全方位的简化&#xff0c;Spring还对常用的功能进行封装&#xff0c;可以极大地提高Java EE的开发效率。 依赖注入是Spring的核心技术之一&#xff0c;也被称为“控制反转”&a…

Element-UI 快速入门指南

文章目录 一、安装 Element-UI1.1 使用 npm 安装1.2 使用 yarn 安装 二、引入 Element-UI三、使用 Element-UI 组件3.1 按钮组件3.2 输入框组件3.3 表单组件3.4 表格组件3.5 弹框组件 四、自定义主题4.1 安装主题工具4.2 初始化变量文件4.3 编译主题 五、总结 &#x1f389;欢迎…

栈:概念与实现,超简单!!!

1.概念 压栈&#xff1a;栈的插入操作叫做进栈/压栈/入栈&#xff0c;入数据在栈顶。出栈&#xff1a;栈的删除操作叫做出栈&#xff0c;出数据也在栈顶。栈的元素遵循后进先出LIFO(Last In First Out)的原则。后面进来的数据先出去 2.栈的实现 三种实现方法&#xff0c;数组…

如何在Springboot项目的Mapper中增加一个新的sql语句

在做项目的过程中&#xff0c;我发现有的时候需要用到一些不在springboot的Mapper中的Sql语句&#xff0c;那么应该如何进行操作呐&#xff1f;&#xff1f; 平常我们创建springbootmybatisPlus项目的时候是这样创建的&#xff1a;&#xff1a; 1、创建实体类 2、创建Mappe…

四川景源畅信:抖音有哪些可以做的副业?

抖音作为当前最受欢迎的短视频平台之一&#xff0c;其巨大的流量和用户基础为许多人提供了副业的机会。那么&#xff0c;在抖音上可以做哪些副业呢? 一、内容创作与推广 利用抖音平台进行内容创作是最直接的副业方式。无论是搞笑短剧、生活分享还是专业知识普及&#xff0c;只…

深入了解 npm 命令

文章目录 安装 npm初始化项目安装包更新包卸载包查看已安装的包查找包其他常用命令结论 在现代 JavaScript 开发中&#xff0c;npm&#xff08;Node Package Manager&#xff09;是一个不可或缺的工具。它是 Node.js 生态系统的一部分&#xff0c;用于管理 JavaScript 包和依赖…

学习中...【京东价格/评论数据】数据获取方式——采用Selenium★

近期闲来无事学学selenium爬虫技术&#xff0c;参考崔庆才《Python3网络爬虫开发实战》的淘宝商品信息爬取&#xff0c;我也照猫画虎的学了京东的价格和商品评论数据。废话不多说&#xff0c;直接开始吧&#xff01; 1. 浏览器初始化 from selenium import webdriver from se…

OSPF基本配置

1.启动OSPF进程 [rijospf1 router-id 1.1.1.1 --- 手工配置RID [r1-ospf-1) 2&#xff0c;创建区域 [r1-ospf-1]area 0 [r1-ospf-1-area-0.0.0.0) 3&#xff0c;宣告 目的:1&#xff0c;只有被宣告网段中的接口才能被激活。 --- 激活接口 ---- 只有激活的接口才能收发OSPF的…

SQL高级语句

主知识点八&#xff1a;窗口函数 新开窗口&#xff0c;不影响原数据的排序。且子句必须有order by。窗口结果返回到 且窗口函数必须写在select后面&#xff01; ● 【排序窗口函数】 ● rank()over()——1,1,3,4 ● dense_rank()over()——1,1,2,3 ● row_number(…

软件3班20240513

java.util.PropertyResourceBundle4554617c package com.yanyu;import java.sql.*; import java.util.ResourceBundle;public class JDBCTest01 {public static void main(String[] args) throws SQLException { // 获取属性配置文件ResourceBundle bundle Res…

【从零开始实现stm32无刷电机foc】【理论】【1/6 电机旋转本质】

目录 电机旋转需要什么样的力&#xff1f;怎么产生力矢量&#xff1f;怎么产生任意的线圈磁矢量&#xff1f; 电机旋转需要什么样的力&#xff1f; 电机切向存在受力&#xff0c;电机就会旋转。 进一步查看电机结构&#xff0c;分为转子和定子&#xff0c;大部分情况下&#…

经典文献阅读之--U-BEV(基于高度感知的鸟瞰图分割和神经地图的重定位)

0. 简介 高效的重定位对于GPS信号不佳或基于传感器的定位失败的智能车辆至关重要。最近&#xff0c;Bird’s-Eye-View (BEV) 分割的进展使得能够准确地估计局部场景的外观&#xff0c;从而有利于车辆的重定位。然而&#xff0c;BEV方法的一个缺点是利用几何约束需要大量的计算…

全方位入门git-慕课网 笔记

目录 【上传github忽略某些文件】【配置用户名和邮箱】【想要删除不需要的文件时如何进行操作】【想要给文件重命名如何操作】【想要移动文件到其他位置时如何操作】【文件有变化时&#xff0c;如何查看前后变化】【操作失误的情况下如何实现一键还原】【不再追踪时如何实现撤销…

MySQL基础入门【mysql初识 | 数据库操作 | 表操作 | sql数据类型】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 一&#xff0c;为什么会有…