聊聊贪心算法

第1部分:引言

贪心算法是一种在每一步选择中都采取当前状态下最优(或最有利)的选择,从而希望导致结果是全局最优的算法策略。这种算法简单、直观,且在很多情况下能够快速得到一个足够好的解决方案。然而,值得注意的是,贪心算法并不保证总是能够得到全局最优解,这取决于问题的性质。

第2部分:贪心算法概述

2.1 定义和特点

贪心算法是一种在每一步选择中都采取当前状态下最优(或最有利)的选择,以期望得到全局最优解的算法策略。它的核心思想是在每一步都做出局部最优的选择,从而希望这些局部最优选择的累积能够导致全局最优解。贪心算法具有以下特点:

  • 直观性:贪心算法的选择过程直观,易于理解和实现。
  • 简单性:算法结构简单,通常只需要线性或多项式时间复杂度。
  • 快速性:能够快速得到解决方案,适合于需要快速响应的场景。
  • 不保证全局最优:由于每一步只考虑局部最优,不保证最终解是全局最优的。
2.2 与其他算法的比较

贪心算法与其他算法如动态规划、回溯算法等有着明显的区别:

  • 动态规划:通常用于求解具有重叠子问题和最优子结构的问题,能够保证找到全局最优解,但计算复杂度较高。
  • 回溯算法:通过探索所有可能的解决方案来寻找最优解,适用于解空间较小的问题,但计算复杂度可能非常高。
  • 贪心算法:适用于解空间较大或需要快速近似解的问题,但不能保证全局最优。
2.3 贪心算法的适用条件

贪心算法适用于满足以下条件的问题:

  • 贪心选择性质:局部最优选择可以导致全局最优解。
  • 最优子结构:问题的最优解包含子问题的最优解。
2.4 贪心算法的分类

根据问题类型和算法结构,贪心算法可以分为以下几类:

  • 背包问题:如0/1背包问题,贪心算法根据物品的价值和体积比进行选择。
  • 区间调度问题:如活动选择问题,贪心算法根据活动的结束时间进行选择。
  • 霍夫曼编码:一种用于数据压缩的贪心算法,根据字符出现的频率进行编码。
2.5 算法流程和伪代码

贪心算法的一般流程如下:

  1. 初始化一个空的解决方案集合。
  2. 遍历所有候选解。
  3. 对于每个候选解,如果它能够使得当前解决方案更优,并且不会违反任何约束,则选择它。
  4. 重复步骤2和3,直到没有更多的候选解可以被选择。

伪代码示例:

function GreedyAlgorithm(candidates):solution = empty setfor each candidate in candidates:if candidate can be added to solution without violating any constraints:add candidate to solutionreturn solution
2.6 编程语言的选择和实现示例

贪心算法可以用多种编程语言实现,如Python、C++、Java等。以下是使用Python实现的一个简单示例,用于解决硬币找零问题:

def min_coins(coins, amount):result = []for coin in sorted(coins, reverse=True):while amount >= coin:result.append(coin)amount -= coinreturn result# 示例:使用面额为1, 5, 10的硬币找零25
coins = [1, 5, 10]
amount = 25
print(min_coins(coins, amount))  # 输出: [10, 10, 5]

第3部分:贪心算法的基本原理

3.1 贪心选择性质

贪心选择性质是贪心算法的核心,它指的是在算法的每一步中,所做的选择是当前状态下的最优选择。这种选择是基于局部最优解来构造全局解的策略。例如,在硬币找零问题中,贪心算法总是优先选择面额最大的硬币,以减少所需硬币的总数。

3.2 最优子结构

最优子结构是指一个问题的最优解包含其子问题的最优解。这是贪心算法适用的一个重要条件。例如,在霍夫曼编码问题中,整个数据的最优编码可以由各个字符的最优编码组合而成。

3.3 贪心算法的局限性

尽管贪心算法在很多情况下都能得到有效的解决方案,但它并不总是能够得到全局最优解。这是因为贪心算法的每一步只考虑当前的最优选择,而忽略了未来可能出现的更好选择。例如,在旅行商问题中,贪心算法可能会选择最近的目的地,但最终的路径可能不是最短的。

3.4 贪心算法的优化策略

为了克服贪心算法的局限性,可以采取以下一些策略:

  • 回溯:在发现当前选择不是最优解时,回溯到上一步重新选择。
  • 分支限界:在搜索过程中,通过剪枝来减少不必要的搜索空间。
  • 启发式搜索:结合贪心算法和其他启发式方法,如模拟退火或遗传算法,来寻找更优解。
3.5 贪心算法的实现步骤

贪心算法的实现通常遵循以下步骤:

  1. 问题建模:将实际问题转化为数学模型,定义候选解集合和目标函数。
  2. 贪心策略定义:确定选择候选解的贪心策略,如根据价值、体积比等。
  3. 算法实现:编写代码实现贪心算法的逻辑。
  4. 结果验证:通过测试用例验证算法的正确性和有效性。
3.6 示例:活动选择问题

活动选择问题是贪心算法的经典应用之一。问题描述是:给定一系列活动,每个活动都有一个开始时间和结束时间,目标是选择最大数量的互不重叠的活动。

def max_activities(activities):activities.sort(key=lambda x: x[1])  # 按结束时间排序selected = [activities[0]]  # 选择第一个活动for activity in activities:if activity[0] >= selected[-1][1]:  # 如果活动开始时间晚于或等于前一个活动的结束时间selected.append(activity)return selected# 示例:选择最大数量的互不重叠的活动
activities = [(1, 4),(3, 5),(0, 6),(5, 7),(3, 9),(5, 9),(6, 10)
]
print(max_activities(activities))  # 输出: [(1, 4), (5, 7), (6, 10)]
3.7 示例:哈夫曼编码

哈夫曼编码是一种用于数据压缩的贪心算法,它通过构造最优的二叉树来为数据中的字符分配编码。

import heapqdef huffman_encoding(data):# 统计每个字符的频率frequency = {}for char in data:frequency[char] = frequency.get(char, 0) + 1# 使用最小堆构建哈夫曼树heap = [[weight, [char, ""]] for char, weight in frequency.items()]heapq.heapify(heap)while len(heap) > 1:lo = heapq.heappop(heap)hi = heapq.heappop(heap)for pair in lo[1:]:pair[1] = '0' + pair[1]for pair in hi[1:]:pair[1] = '1' + pair[1]heapq.heappush(heap, [lo[0] + hi[0]] + lo[1:] + hi[1:])return sorted(frequency.items(), key=lambda x: x[0])# 示例:对字符串进行哈夫曼编码
data = "this is an example for huffman encoding"
encoded = huffman_encoding(data)
print(encoded)  # 输出: 编码后的字符和对应的编码字符串

第4部分:贪心算法的分类与实现

4.1 引言

在深入理解了贪心算法的基本原理之后,我们接下来探讨贪心算法的不同分类以及如何实现它们。贪心算法可以根据解决的问题类型和算法结构进行分类,每种分类都有其特定的应用场景和实现方法。

4.2 贪心算法的分类
  1. 背包问题:如0/1背包问题,每个物品可以选择拿或不拿,目标是使得总价值最大。
  2. 区间调度问题:如活动选择问题,选择不相互重叠的区间活动,以最大化活动数量。
  3. 图论问题:如最小生成树问题,使用贪心算法在图的顶点之间找到一棵连接所有顶点的最小权重树。
  4. 霍夫曼编码:一种用于数据压缩的贪心算法,通过构建最优二叉树来为字符分配编码。
4.3 背包问题的实现

背包问题可以通过贪心算法来解决,特别是当物品不可分割时(0/1背包问题)。以下是一个使用Python实现的0/1背包问题示例:

def knapsack_01(weights, values, capacity):items = range(len(values))items.sort(key=lambda i: values[i] / weights[i], reverse=True)total_value = 0for i in items:if weights[i] <= capacity:capacity -= weights[i]total_value += values[i]return total_value# 示例:0/1背包问题
weights = [10, 20, 30]
values = [60, 100, 120]
capacity = 50
print(knapsack_01(weights, values, capacity))  # 输出: 220
4.4 区间调度问题的实现

活动选择问题是一种典型的区间调度问题,可以通过贪心算法来解决。以下是一个使用Python实现的活动选择问题示例:

def schedule_activities(activities):activities.sort(key=lambda x: x[1])  # 按结束时间排序selected = [activities[0]]  # 选择第一个活动for activity in activities[1:]:if activity[0] >= selected[-1][1]:  # 如果当前活动的开始时间晚于或等于最后一个选择的活动的结束时间selected.append(activity)return selected# 示例:活动选择问题
activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (6, 10)]
print(schedule_activities(activities))  # 输出: [(1, 4), (5, 7), (6, 10)]
4.5 最小生成树问题的实现

最小生成树问题可以通过Kruskal算法或Prim算法来解决,它们都是基于贪心策略的。以下是一个使用Kruskal算法的Python实现示例:

def find(parent, x):if parent[x] != x:parent[x] = find(parent, parent[x])return parent[x]def union(parent, rank, x, y):xroot = find(parent, x)yroot = find(parent, y)if rank[xroot] < rank[yroot]:parent[xroot] = yrootelif rank[xroot] > rank[yroot]:parent[yroot] = xrootelse:parent[yroot] = xrootrank[xroot] += 1def kruskal(graph):result = []  # This will store the resultant MSTedges = []  # To store all the edges sorted on the basis of their weightfor u in graph:for v, w in graph[u]:edges.append((w, u, v))edges.sort()  # Sort all the edges on the basis of their weightsparent = {}rank = {}for vertex in graph:parent[vertex] = vertexrank[vertex] = 0i = 0while i < len(edges) and len(result) < len(graph) - 1:w, u, v = edges[i]i += 1x = find(parent, u)y = find(parent, v)if x != y:result.append((u, v, w))union(parent, rank, x, y)return result# 示例:最小生成树问题
graph = {'A': [('B', 1), ('C', 3)],'B': [('A', 1), ('C', 2), ('D', 4)],'C': [('A', 3), ('B', 2), ('D', 5)],'D': [('B', 4), ('C', 5)]
}
print(kruskal(graph))  # 输出: 最小生成树的边和权重
4.6 霍夫曼编码的实现

霍夫曼编码是一种用于数据压缩的贪心算法,以下是一个使用Python实现的霍夫曼编码示例:

class Node:def __init__(self, char, freq):self.char = charself.freq = freqself.left = Noneself.right = Nonedef huffman_encoding(data):frequency = {}for char in data:frequency[char] = frequency.get(char, 0) + 1priority_queue = [Node(char, freq) for char, freq in frequency.items()]heapq.heapify(priority_queue)while len(priority_queue) > 1:left = heapq.heappop(priority_queue)right = heapq.heappop(priority_queue)merged = Node(None, left.freq + right.freq)merged.left = leftmerged.right = rightheapq.heappush(priority_queue, merged)root = priority_queue[0]codes = {root.char: ''}def get_codes(node, current_code):if node is None:returnif node.char is not None:codes[node.char] = current_codeget_codes(node.left, current_code + '0')get_codes(node.right, current_code + '1')get_codes(root, '')return codes# 示例:霍夫曼编码
data = "this is an example for huffman encoding"
codes = huffman_encoding(data)
print(codes)  # 输出: 字符和对应的霍夫曼编码

看到这,欢迎友友们关注我的公众号:行动圆周率
或扫描关注
在这里插入图片描述

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

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

相关文章

el-upload 组件上传文件(查询,上传,删除,下载功能)

1.html el-upload中的属性&#xff1a; <el-upload ref"upload" class"upload-demo" // element-ui自带的样式 :headers"headerOdj" // 文件上传的头,带token&#xff08;重要&#xff0c;不然传输大文件会断掉&…

Shell编程规范与变量-01

一、Shell脚本概述 在一些复杂的 Linux 维护工作中&#xff0c;大量重复性的输入和交互操作不仅费时费力&#xff0c;而且容易出错&#xff0c;而编写一个恰到好处的 Shell 脚本程序&#xff0c;可以批量处理、自动化地完成一系列维护任务&#xff0c;大大减轻管理员的负担。 1…

mongosh 和mongo 命令行连接MongoDB

Mongoshell MongoDB的Shell工具mongosh是一个全功能的JavaScript和Node.js的14.x REPL与MongoDB的部署交互环境。我们通过它可以直接对数据库进行查询和操作。这个工具是需要在安装玩MongoDB后单独安装的。 与传统的mongo方式连接MongoDB更加丰富。 官网 https://www.mongodb.…

Java 面试题:如何保证集合是线程安全的? ConcurrentHashMap 如何实现高效地线程安全?

在多线程编程中&#xff0c;保证集合的线程安全是一个常见而又重要的问题。线程安全意味着多个线程可以同时访问集合而不会导致数据不一致或程序崩溃。在 Java 中&#xff0c;确保集合线程安全的方法有多种&#xff0c;包括使用同步包装类、锁机制以及并发集合类。 最简单的方法…

编程语言中的作用域

编程语言中的作用域 作用域&#xff08;Scope&#xff09;是计算机程序设计中的一个核心概念&#xff0c;它主要用于规定程序中变量、函数和对象的可见范围和有效期限。换句话说&#xff0c;作用域决定了在代码的哪些部分可以访问特定的变量、函数或对象。 通过作用域的使用&…

网络编程(八)广播、组播

一、广播 &#xff08;一&#xff09;概念 前面介绍的数据包发送方式只有一个接受方&#xff0c;称为单播 如果同时发给局域网中的所有主机&#xff0c;称为广播 如果同时发给局域网中的部分主机&#xff0c;称为组播 注意&#xff1a; 只有用户数据报(使用UDP协议)套接字才…

AI音乐大模型时代:版权归属与创意产业的新生长点

AI在创造还是毁掉音乐&#xff1f; 简介&#xff1a;最近一个月&#xff0c;轮番上线的音乐大模型&#xff0c;一举将素人生产音乐的门槛降到了最低&#xff0c;并掀起了音乐圈会不会被AI彻底颠覆的讨论。短暂的兴奋后&#xff0c;AI产品的版权归属于谁&#xff0c;创意产业要…

JWT生成令牌

实现步骤 引入JWT包 <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.12.3</version> </dependency>定义令牌类型枚举 package com.angel.ocean.token.constant;public enum Toke…

go语言进阶实战学习(逐行注释)(1):两协程并发交替打印数字和字母

要求&#xff1a; 并发两协程交替打印数字和字母。一个协程打印数字&#xff0c;一个协程打印字母。 输出&#xff1a; 12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728 思路&#xff1a; 两个 channel 控制两个协程进行交替打印。sync.WaitG…

PyScada(三)后端应用

PyScada 的后端应用 使用后端 要使用后端&#xff0c;请在浏览器中打开http://127.0.0.1 &#xff08;将 127.0.0.1 替换为 PyScada 服务器的 IP 或主机名&#xff09;&#xff0c;然后使用安装过程 中定义的管理员帐户登录 &#xff08;TODO 链接到创建超级用户文档&#xf…

Java基础的重点知识-01

文章目录 开发前言Java语言开发环境入门程序说明常量变量和数据类型数据类型转换运算符方法解析 开发前言 常用DOS命令 Java语言的初学者&#xff0c;学习一些DOS命令&#xff0c;会非常有帮助。DOS是一个早期的操作系统&#xff0c;现在已经被Windows系统取代&#xff0c;对于…

STL——函数对象,谓词

一、函数对象 1.函数对象概念 概念&#xff1a; 重载函数调用操作符的类&#xff0c;其对象常称为函数对象。 函数对象使用重载的()时&#xff0c;行为类似函数调用&#xff0c;也叫仿函数。 本质&#xff1a; 函数对象(仿函数)是一个类&#xff0c;不是一个函数。 2.函数对象…

Vue2动态代理无须重启项目解决方案

1、痛点 如果我们需要使用不同的环境地址的时候&#xff0c;就需要使用命令或者手动修改vue.config.js中配置来重新启动项目。当项目项目越来越大的时候&#xff0c;我们需要很长的时间来启动项目&#xff0c;如此反复&#xff0c;极大影响我们开发进度。 2、寻求解决方案 ● v…

RAG和agent框架选型

langChain llama index autoGen metaGPT

spring使用@PostConstruct踩得坑

情况说明&#xff1a; 在一个抽象类中使用PostConstruct注解方法init用于初始化操作。然后每个实现类在初始化时都会调用PostConstruct注解的init方法执行初始化操作。如下代码&#xff1a; public abstract class AbstractClass {/*** 存放各实例.*/public static final Map&…

git分支及提交规范【AI 文心一言】

Git代码提交规范和分支命名规范是团队协作中非常重要的部分&#xff0c;它们有助于保持代码库的清晰、一致和易于管理。以下是对Git代码提交规范和采用“/”分割的分支命名规范的总结&#xff1a; Git代码提交规范 提交类型&#xff1a; feat: 增加新功能 fix: 修复问题BUG d…

Windows安装多个jdk环境(jdk6+jdk8+jdk17)保姆级

Windows安装多个jdk环境&#xff08;jdk6jdk8jdk17&#xff09;保姆级 背景&#xff1a;新机安装开发环境发现需要找很多文章&#xff0c;&#xff0c;&#xff0c;&#xff0c;这里一篇文章安装所有环境 文章目录 Windows安装多个jdk环境&#xff08;jdk6jdk8jdk17&#xff09…

经典游戏案例:植物大战僵尸

学习目标&#xff1a;植物大战僵尸核心玩法实现 游戏画面 项目结构目录 部分核心代码 using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using Random UnityEngine.Random;public enum Z…

Django 条件判断模板标签

1&#xff0c;条件判断模板标签 1. 2 {% if %} 标签 {% if variable %}<!-- 如果 variable 为 True&#xff0c;则渲染此处内容 --> {% endif %} 1. 3 {% if %} 与 {% else %} 组合 {% if variable %}<!-- 如果 variable 为 True&#xff0c;则渲染此处内容 -->…

【笔记】git源

报错信息 # git clone https://github.com/paddlepaddle/PaddleCustomDevice Cloning into PaddleCustomDevice... error: RPC failed; curl 16 Error in the HTTP2 framing layer fatal: expected flush after ref listing可选源 由于&#x1f512;&#x1f5fa;&#xff0c…