数据结构与算法(三)贪心算法(Java)

目录

    • 一、简介
      • 1.1 定义
      • 1.2 基本步骤
      • 1.3 优缺点
    • 二、经典示例
      • 2.1 选择排序
      • 2.2 背包问题
    • 三、经典反例:找零钱
      • 3.1 题目
      • 3.2 解答
      • 3.3 记忆化搜索实现
      • 3.4 动态规划实现

一、简介

1.1 定义

贪心算法(Greedy Algorithm),又名贪婪法,是寻找 最优解问题 的常用方法。

  • 将求解过程 分成若干个步骤,每个步骤都应用贪心原则,选取当前状况下最好/最有的选择(局部最有利的选择),并以此希望最后堆叠出的结果也是最好/最优的解。

1.2 基本步骤

  • 步骤1:从某个初始解出发;
  • 步骤2:把求解的问题分成若干个子问题;
  • 步骤3:对每一子问题求解,得到子问题的局部最优解;
  • 步骤4:把子问题的局部最优解合成原来问题的一个解。

1.3 优缺点

优点:

  • 简单、高效,省去为了寻找最优解可能需要穷举的操作,通常作为其他算法的辅助算法来使用

缺点:

  • 不从整体上考虑其它可能情况,每次选取局部最优解,不再进行回溯处理,所以 并非一定能得到整体最优解

二、经典示例

2.1 选择排序

没错,我们常见的选择排序就是运用了贪心算法的思想。

题目:

  • 实现数字数组递增排序。

解答:

从数组的零下标开始,依次从后面找到最小的元素下标与当前位置的元素互换,这个在后面寻找最小元素的过程就是贪心的思想。

贪心策略寻找最小的元素,(贪心地)认定此元素就是当前位置的最小元素,然后遍历每一个位置。

public void choiceSort(int[] arr) {for (int i = 0; i < arr.length; i++) {int minIndex = i;for (int j = i + 1; j < arr.length; j++) {minIndex = arr[j] < arr[minIndex] ? j : minIndex;}if (minIndex != i) {int tmp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = tmp;}}
}

2.2 背包问题

题目:

有一个背包,容量由你自己输入,有n个物品,每个物品都具有容量与价值,这些都是由你自己输入的,请问,要怎么放物品到背包里,才能使得总价值最大呢,放入背包的总容量要小于等于背包的总容量。(如果一个物品放不下,则可以拆分成多个小块)
背包:M:100
物品:N:7
重量 价值
10 20
20 40
30 30
25 20
50 40
10 35
60 70

解答:

每个物品都具有自己的重量与价格,不妨计算出每个物品的单位价值。

  • 单位价值: 价值/重量,即每份重量的价值。

然后我们将这些物品 按照单位价值递减排序。这样一来就简单了,只需用贪心算法,依次把最大单位价值的物品价值和重量相加 就行了。

贪心策略:单位价值最大的物品,我们假设它就是最好的,直接把它放在背包里面。

public static void main(String[] args) {int[][] items = new int[7][2];items[0][0] = 10; items[0][1] = 20;items[1][0] = 20; items[1][1] = 40;items[2][0] = 30; items[2][1] = 30;items[3][0] = 25; items[3][1] = 20;items[4][0] = 50; items[4][1] = 40;items[5][0] = 10; items[5][1] = 35;items[6][0] = 60; items[6][1] = 70;int capacity = 100;System.out.println("背包的容量:" + capacity);StringBuilder builder = new StringBuilder();for (int[] item : items) {builder.append(Arrays.toString(item));}System.out.println(items.length + " 个物品的重量、价值:" + builder.toString());int maxValue = maxValue(items, capacity);System.out.println("最大价值:" + maxValue);
}public static int maxValue(int[][] items, int capacity) {// 计算单位价值double[] prices = new double[items.length];Map<Double, List<Integer>> positionMap = new HashMap<>(items.length);for (int i = 0; i < items.length; i++) {prices[i] = 1.0 * items[i][1] / items[i][0];List<Integer> positions = positionMap.getOrDefault(prices[i], new ArrayList<>());positions.add(i);positionMap.put(prices[i], positions);}// 排序Arrays.sort(prices);int weight = 0;int maxValue = 0;for (int i = prices.length - 1; i >= 0; i--) {List<Integer> positions = positionMap.get(prices[i]);if (positions != null) {Integer position = positions.remove(0);if (positions.size() == 0) {positionMap.remove(prices[i]);}if (weight + items[position][1] < capacity) {weight += items[position][0];maxValue += items[position][1];System.out.println("重量为 " + items[position][0] + ",价值为 " + items[position][1] + " 的物品被放入背包,剩余容量:" + (capacity - weight));}}}return maxValue;
}

执行结果:

在这里插入图片描述


三、经典反例:找零钱

322. 零钱兑换

3.1 题目

假设你开了间小店,不能电子支付,钱柜里的货币只有 25 分、20分、10 分、5 分和 1 分 四种硬币,如果你是售货员且要找给客户 41 分钱的硬币,如何安排才能找给客人的钱既 正确 且硬币的个数又 最少

3.2 解答

我们看到这种题目可能第一个想法就是用 贪心算法 进行解决,其实不然,由于贪心算法不能进行回溯处理,所以并不能取得最优解。

  • 41 分钱按照贪心算法,先找 25分,剩余 16分,再找 10分、5分、1分,共需要 4 枚硬币。
  • 实际情况下,我们只需要找两个 20分钱,再找一个 1分钱就够了,共需要 3 枚硬币。

那么不用贪心算法,应该用什么算法呢?其实有两种方法可以解决:

  • 一是 贪心+回溯,即 记忆化搜索
  • 二是 动态规划

3.3 记忆化搜索实现

  • 记忆化搜索实现方式,就是自顶向下遍历,先查用完一枚硬币之后还剩多少钱,再根据剩余的钱进行迭代。

代码实现需要注意以下几点:

  • int[] 类型数组初始化值为0;
  • 针对需要记忆的组合,不光要记忆成功的情况,失败的情况也要记录。
class Solution {public static void main(String[] args) {int amount = 41;int[] arr1 = {1, 5, 10, 20, 25};System.out.println("零钱总数为:" + amount);System.out.println("硬币面值为:" + Arrays.toString(arr1));int result1 = coinChange(arr1, amount);System.out.println("最少使用硬币数:" + result1);}public static int coinChange(int[] coins, int amount) {if (amount == 0) {return 0;}return handleCoin(coins, new int[amount], amount);}private static int handleCoin(int[] coins, int[] his, int coinAmount) {if (coinAmount < 0) {return -1;}if (coinAmount == 0) {return 0;}if (his[coinAmount - 1] != 0) {return his[coinAmount - 1];}int minCount = Integer.MAX_VALUE;for (int coin : coins) {int tmpMinCount = handleCoin(coins, his, coinAmount - coin);if (tmpMinCount != -1 && tmpMinCount + 1 < minCount) {minCount = tmpMinCount + 1;}}his[coinAmount - 1] = minCount == Integer.MAX_VALUE ? -1 : minCount;return his[coinAmount - 1];}
}

执行结果:

在这里插入图片描述

3.4 动态规划实现

  • 动态规划实现,则是自底向上,先计算从1开始每个金额所需的最小零钱数,直到找到需要的钱数,过程中对于剩余钱数所需要的最小零钱数可以直接使用前面计算好的数据。

代码实现需要注意以下几点:

  • 对于数值类型的映射,不要用 Map 类型,用 int[] 类型效率更高;
  • 在循环迭代的过程中,只需要加硬币数就可以了,不用再去迭代考虑其他的组合。
class Solution {public static void main(String[] args) {int amount = 41;int[] arr1 = {1, 5, 10, 20, 25};System.out.println("零钱总数为:" + amount);System.out.println("硬币面值为:" + Arrays.toString(arr1));int result1 = coinChange(arr1, amount);System.out.println("最少使用硬币数:" + result1);}public static int coinChange(int[] coins, int amount) {// k-零钱和,v-最小零钱量int[] his = new int[amount + 1];Arrays.fill(his, amount + 1);his[0] = 0;for (int i = 1; i <= amount; i++) {for (int coin : coins) {if (coin <= i) {his[i] = Math.min(his[i], his[i - coin] + 1);}}}return his[amount] == amount + 1 ? -1 : his[amount];}
}

执行结果:

在这里插入图片描述

整理完毕,完结撒花~ 🌻





参考地址:

1.小白带你学—贪心算法(Greedy Algorithm),https://zhuanlan.zhihu.com/p/53334049

2.贪心算法思想详解+示例代码,https://blog.csdn.net/jj6666djdbbd/article/details/126971331

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

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

相关文章

串口波形延时问题再次故障测试分析

先放电路图吧 这个延时问题测试了很多天&#xff0c;怎么感觉总是有没有想到的问题可以测试&#xff0c;总是有原件可以替换改善问题&#xff0c;再次测试了三极管的C脚波形&#xff1a; 从上到下的3个波形分别是MCU出来的波形&#xff0c;经过三极管反向的波形&#xff0c;…

2.ORB-SLAM3中如何从二进制文件中加载多地图、关键帧、地图点等数据结构

目录 1 为什么保存&加载(视觉)地图 1.1 加载多地图的主函数 1.2 加载各个地图 Atlas::PostLoad 1.3 加载关键帧及地图点Map::PostLoad 1.4 恢复地图点信息 MapPoint::PostLoad 1.5 恢复关键帧信息KeyFrame::PostLoad 1 为什么保存&加载(视觉)地图 因为我们要去做导…

抽象类的使用—模板设计模式 Java

模板设计模式 一、引入二、改进 一、引入 需求 ① 有多个类&#xff0c;完成不同的任务 job ② 要求统计得到各自完成任务的时间 ③ 请编程实现 >最容易想到的方法&#xff0c;写类&#xff0c;统计时间 AA BB中的 job 方法中是有重复的。 >改进1&#xff1a;每个类中&…

SpringBoot整合EasyExcel实现复杂Excel表格的导入导出功能

文章目录 &#x1f389;SpringBoot整合EasyExcel实现复杂Excel表格的导入&导出功能 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;IT陈寒的博客&#x1f388;该系列文章专栏&#xff1a;架构设计&#x1f4dc;其他专栏&#xff1a;Java学习路线 Jav…

集成IDE开发环境,Java开发工具IntelliJ IDEA 2023中文

IntelliJ IDEA 2023是一款功能强大的软件&#xff0c;其为程序员提供了一款先进的集成开发环境。它以智能、高效和人性化为主要特点&#xff0c;致力于提高开发人员的生产力&#xff0c;帮助程序员更快、更好地编写代码。IntelliJ IDEA 2023支持多种语言和框架&#xff0c;包括…

继承JsonSerializer+注解实现自定义数据脱敏方案

1、数据脱敏 数据脱敏是一种保护隐私数据的技术&#xff0c;通过将敏感信息转化为非敏感信息来实现对数据的保护&#xff0c;以保护敏感隐私数据的可靠性和安全性。 数据脱敏可以分为可恢复和不可恢复两类: 可恢复类可以通过一定的方式恢复成原来的敏感数据。不可恢复类则无…

【Shell】Shell基础学习

一、shell脚本 (1)第一个shell脚本 #!/bin/bash #this is a comment echo "hello world"一个shell脚本永远以“#!”开头,这是一个脚本开始的标记,它是告诉系统执行这个文件需要用某个解释器,后面的/bin/bash就是指明解释器的具体位置。 “#”开头是注释 …

P8A003-系统加固-系统管理员账户安全

【预备知识】 Administrator 原意为管理人或行政官员或遗产管理人&#xff0c;在计算机名词中&#xff0c;它的意思是系统超级管理员或超级用户。但是在Windows系统中此用户名只在安全模式中使用。 【实验步骤】 网络拓扑&#xff1a;server2008-basic windows server 2008 …

LeetCode [简单]118. 杨辉三角

给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 public class Solution {public IList<IList<int>> Generate(int numRows) {List<IList<int>> res new …

交流负载测试使用场景

交流负载测试是一种在特定环境下&#xff0c;对电力设备、汽车电子部件&#xff0c;工业自动化设备、网络设备、家电产品&#xff0c;航空航天设备以及医疗器械等产品进行测试的方法&#xff0c;该测试的目的是评估这些设备在实际运行条件下的性能和可靠性。 1电力设备测试 交…

Zabbix 6.0 详细基础介绍

目录 一、如何选择自己的运维监控平台 1.1 常用的开源运维监控工具 1.1.1 Cacti 1.1.2 Nagios 1.1.3 Ganglia 1.1.4 Centreon 1.1.5 Grafana 1.1.6 Prometheus 1.1.7 Zabbix 1.2 监控工具选型经验 1.2.1 中小企业传统监控选择 Zabbix 1.2.2 云原生监控选择 Prometh…

虚幻学习笔记2—点击场景3D物体的两种处理方式

一、前言 本文使用的虚幻引擎为5.3.2&#xff0c;两种方式分别为&#xff1a;点击根物体和精准点击目标物体。 二、实现 2.1、玩家控制器中勾选鼠标点击事件&#xff1a;这一步很重要&#xff0c;如图2.1.1所示&#xff1a;在自定义玩家控制器中勾 图2.1.1 选该项&#xff0c…

GPT实战系列-GPT训练的Pretraining,SFT,Reward Modeling,RLHF

GPT实战系列-GPT训练的Pretraining&#xff0c;SFT&#xff0c;Reward Modeling&#xff0c;RLHF 文章目录 GPT实战系列-GPT训练的Pretraining&#xff0c;SFT&#xff0c;Reward Modeling&#xff0c;RLHFPretraining 预训练阶段Supervised FineTuning &#xff08;SFT&#x…

Vue 3 面试经验分享

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

docker容器运维操作命令

docker exec &#xff1a;在运行的容器中执行命令 docker exec [OPTIONS] CONTAINER COMMAND [ARG...] OPTIONS说明&#xff1a; -d :分离模式: 在后台运行 -i :即使没有附加也保持STDIN 打开 -t :分配一个伪终端docker ps : 列出容器 docker ps [OPTIONS] OPTIONS说明&#…

【EI会议投稿】第四届物联网与智慧城市国际学术会议(IoTSC 2024)

第四届物联网与智慧城市国际学术会议 2024 4th International Conference on Internet of Things and Smart City 继IoTSC前三届的成功举办&#xff0c;第四届物联网与智慧城市国际学术会议&#xff08;IoTSC 2024&#xff09;将于2024年3月22-24日在河南洛阳举办。 智慧城市的…

Oracle ORA12514 监听程序当前无法识别连接描述符中请求的服务

最简单的有可能是你的服务还没有开启&#xff0c;需要启动服务&#xff01;&#xff01;&#xff01;&#xff01; 在连接数据库的时候&#xff0c;有时会遇到一个“ORA12514&#xff1a;监听程序当前无法识别连接描述符中请求的服务”的错误&#xff0c;这个错误其实就是数据…

二十章多线程

概念 有很多工作是可以同时完成的&#xff0c;这种思想放在Java中被称为并发&#xff0c;并发完成每一件事被称为线程。 程序员可以在程序中执行多个线程&#xff0c;每一个线程完成一个功能//与其他线程并发执行&#xff0c;这种机制被称为多线程&#xff0c;并不算所有编程…

Echarts大屏可视化_02 球体模块制作

继续跟着b站大佬pink老师学大屏可视化 球体模块制作 1.球体模块布局 HTML <div class"column"><div class"no"><div class"no-hd"><ul><li>125811</li><li>104563</li></ul></div&g…

Mysql解决随机选取问题

常规的随机选取效率差的原因&#xff1a; 两种解决方法&#xff1a; 总结&#xff1a;