Python数据结构与算法——算法(贪心算法、动态规划

贪心算法

介绍:贪心算法又称贪婪算法,是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的是在某种意义上的局部最优解。

贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算。

例一:找零问题

问题:假设商店老板需要找零n元钱,钱币的面额有:100元、50元、20元、5元、1元,如何找零使得所需的钱币数量最少?

思路:为了找的钱币最少,从最大面额找,找不开就用比它小的找...

t = [100, 50, 20, 5, 1]def change(t, n):m = [0 for _ in range(len(t))]for i, money in enumerate(t):m[i] = n // moneyn = n % moneyreturn m, nprint(change(t, 376))

 例二:背包问题

问题:一个小偷在某个商店发现有n个商品,第i个商品价值vi元,重wi千克。他希望拿走的价值尽量高,但他的背包最多只能容纳W千克的东西。他应该拿走哪些商品?

  • 0-1背包:对于一个商品,小偷要么把它完整拿走,要么留下。不能只拿走一部分,或把一个商品拿走多次。(商品为金条)
  • 分数背包:对于一个商品,小偷可以拿走其中任意一部分。(商品为金砂)

分数背包使用贪心算法没有问题,但是0-1背包不可以!

分数背包

goods = [(60, 10), (120, 30), (100, 20)]  # 每个商品元组表示(价格, 重量)
goods.sort(key = lambda x:x[0]/x[1], reverse = True)  # 按照单价排序def fractional_backpack(goods, w):    m = [0 for _ in range(len(goods))]total_v = 0for i, (price, weight) in enumerate(goods):if w >= weight:m[i] = 1w -= weighttotal_v += priceelse:m[i] = w/weighttotal_v += m[i] * pricew = 0breakreturn m, total_vprint(fractional_backpack(goods, 50))

例三:拼接最大数字问题 、

问题:有n个非负整数,将其按照字符串拼接的方式拼接为一个整数,如何拼接可以使得到的整数最大?

  • 例:32、94、128、1286、6、71可以拼接的最大整数为:94716321286128
from functools import cmp_to_keyli = [32, 94, 128, 1286, 6, 71]def xy_cmp(x, y):if x+y > y+x:return -1elif x+y < y+x:return 1else:return 0def number_join(li):li = list(map(str, li))li.sort(key=cmp_to_key(xy_cmp))return "".join(li)print(number_join(li))

例四:活动选择问题 

问题:假设有n个活动,这些活动要占用同一片场地,而场地在某时刻只能供一个活动使用。

每个活动都有一个开始时间si和结束时间fi(题目中时间以整数表示),表示活动在[si, fi)区间占用场地。

问:安排那些活动能够使该场地举办的活动个数最多?

i1234567891011
si130535688212
fi4567991011121416

思路:最先结束的活动一定是最优解的一部分。

activities = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (5, 9), (6, 10), (8, 11), (8, 12), (2, 14), (12, 16)]# 保证活动是按照结束时间排好序的
activities.sort(key=lambda x:x[1])def activity_selection(a):res = [a[0]]for i in range(1, len(a)):if a[i][0] >= res[-1][1]:  # 当前活动的开始时间小于等于最后一个入选活动的结束时间res.append(a[i])return resprint(activity_selection(activities))

动态规划

介绍:是一种解决复杂问题的数学方法,通常用于优化问题。动态规划将问题分解为更小的子问题,通过解决这些子问题并将它们的解存储起来,最终得到原始问题的解。

思想:

  • 最优子结构(递推式)
  • 重复子问题

什么问题使用动态规划方法?

  • 最优子结构
    • 原问题的最优解中涉及多少个子问题
    • 在确定最优解使用哪些子问题时,需要考虑多少种选择
  • 重叠子问题

例一:斐波那契数列

# 子问题的重复计算
def fibnacci(n):if n == 1 or n == 2:return 1else:return fibnacci(n-1) + fibnacci(n-2)# 无重复计算,存在列表中——动态规划(DP)
def fibnacci_no_recurision(n):f = [0, 1, 1]if n > 2:for i in range(n-2):num = f[-1] + f[-2]f.append(num)return f[-1]print(fibnacci_no_recurision(100))

例二:钢条切割问题

思路:

  • 设长度为n的钢条切割后的最优收益值为r_{n},可以得出递推式:r_{n} = max(p_{n}, r_{1} + r_{n-1}, r_{2} + r_{n-2}, ... , r_{n-1} + r_{1})
  • 第一个参数p_{n }表示不切割
  • 其他n-1个参数分别表示另外n-1种不同切割方案,对方案i=1,2,...,n-1
    • 将钢条切割为长度为i和n-i两段
    • 方案i的收益为切割两端的最优收益之和
  • 考察所有的i,选择其中收益最大的方案

钢条切割问题满足最优子结构,比如长度为9要切为8和1,前面已经算了8的最佳情况,直接使用即可。

自顶向下递归实现

时间复杂度:2^{n}

p = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 27, 28, 30, 33, 36, 39, 40]def cut_rod_recurision_1(p, n):if n == 0:return 0else:res = p[n]for i in range(1, n):res = max(res, cut_rod_recurision_1(p, i) + cut_rod_recurision_1(p, n-i))return resdef cut_rod_recurision_2(p, n):if n == 0:return 0else:res = 0for i in range(1, n+1):res = max(res, p[i] + cut_rod_recurision_2(p, n-i))return resprint(cut_rod_recurision_1(p, 15))
print(cut_rod_recurision_2(p, 15))

自底向上动态规划实现

时间复杂度:n^{2}

p = [0, 1, 5, 8, 9, 10, 17, 17, 20, 21, 23, 24, 26, 27, 27, 28, 30, 33, 36, 39, 40]def cut_rod_dp(p, n):r = [0]for i in range(1, n+1):res = 0for j in range(1, i+1):res = max(res, p[j] + r[i-j])r.append(res)return r[n]print(cut_rod_dp(p, 9))

重构解

同时输出最优解和最优切割方案

  • 对于每个子问题,保存切割一次时左边切下的长度

def cut_rod_extend(p, n):r = [0]s = [0]for i in range(1, n+1):res_r = 0  # 记录价格的最大值res_s = 0  # 记录价格最大值对应方案的左边不切割部分的长度for j in range(1, i+1):if p[j] + r[i-j] > res_r:res_r = p[j] + r[i-j]res_s = jr.append(res_r)s.append(res_s)return r[n], sdef cut_rod_solution(p, n):r, s = cut_rod_extend(p, n)ans = []while n > 0:ans.append(s[n])n -= s[n]return ansprint(cut_rod_solution(p, 9))

例三:最长公共子序列实现

问题:一个序列的子序列是在该序列中删去若干元素后得到的序列。

        例:"ABCD"和"BDF"都是"ABCDEFG"的子序列

给定两个序列X和Y,求X和Y长度最大的公共子序列

返回最大公共子序列长度

def lcs_length(x, y):m = len(x)n = len(y)# 创建一个二维数组来存储子问题的解dp = [[0] * (n + 1) for _ in range(m + 1)]# 填充dp数组for i in range(1, m + 1):for j in range(1, n + 1):if x[i - 1] == y[j - 1]:dp[i][j] = dp[i - 1][j - 1] + 1  # i j 位置上的字符匹配时,来自与左上方else:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])# 从dp数组中找到最长公共子序列的长度return dp[m][n]# 测试
x = "abcde"
y = "ace"
print(lcs_length(x, y))

 

代码自己手动敲一遍理解更深哦!

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

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

相关文章

LangChain-18 Caching 将回答内容进行缓存 可在内存中或数据库中持久化缓存

背景描述 可以将问答的内容缓存起来&#xff0c;如果是相同的问题&#xff0c;那么将会直接把答案返回去&#xff0c;可以节约费用和计算。 安装依赖 pip install -qU langchain-core langchain-openai编写代码 我们可以通过 InMemoryCache 进行内存缓存 或者 SQLiteCache …

电脑无法开机?原因分析与解决方案

电脑无法开机是一种常见的问题&#xff0c;可能会给用户带来诸多困扰。无法启动可能是由于硬件故障、软件问题或者其他未知原因引起的。在本文中&#xff0c;我们将介绍三种常见的方法来解决电脑无法开机的问题&#xff0c;以帮助用户尽快恢复正常使用。 方法1&#xff1a;检查…

spfa算法(java代码)

题目: 851. spfa求最短路 - AcWing题库 输入样例: 3 3 1 2 5 2 3 -3 1 3 4 输出样例: 2 分析&#xff1a; 先去定义一个class 类似于c里面的pair 里面有两个变量x, y 因为后面需要用优先队列来处理最短路问题需要指出比较x还是y 因此我们让这个pair类实现 Comparable 接口 实…

HarmonyOS实战开发-WebSocket的使用。

介绍 本示例展示了WebSocket的使用&#xff0c;包括客户端与服务端的连接和断开以及客户端数据的接收和发送。 WebSocket连接&#xff1a;使用WebSocket建立服务器与客户端的双向连接&#xff0c;需要先通过createWebSocket方法创建WebSocket对象&#xff0c;然后通过connect…

数据应用OneID:ID-Mapping Spark GraphX实现

前言 说明 以用户实体为例&#xff0c;ID 类型包含 user_id 和 device_id。当然还有其他类型id。不同id可以获取到的阶段、生命周期均不相同。 device_id 生命周期通常指的是一个设备从首次被识别到不再活跃的整个时间段。 user_id是用户登录之后系统分配的唯一标识&#xff…

Ubuntu (Linux系统) 下载安装 Qt 环境

在官网http://download.qt.io/archive/qt/ 下载安装包&#xff0c;默认linux平台下提供的安装包以run后缀结尾 也可以选择其它地址下载 Qt官网下载地址&#xff1a;https://download.qt.io&#xff1b; 国内镜像下载地址&#xff1a;https://mirrors.cloud.tencent.com/qt/ 。建…

【牛客SQL快速入门】SQL基础(三)

一、条件函数 IF 条件函数 IF函数是最常用到的条件函数&#xff0c;写法为 if(xn,a,b)&#xff0c;xn代表判断条件&#xff0c;如果xn时&#xff0c;那么结果返回a&#xff0c;否则返回b。 -- 把非北京大学的用户统一归为其他大学 Select device_id,if(university ‘北京大…

nginx反向代理conf

打开nginx配置。 对登录功能测试完毕后&#xff0c;接下来&#xff0c;我们思考一个问题&#xff1a;前端发送的请求&#xff0c;是如何请求到后端服务的&#xff1f; 前端请求地址&#xff1a;http://localhost/api/employee/login 后端接口地址&#xff1a;http://localho…

Java中队列

队列是一种常见的数据结构&#xff0c;它按照先进先出&#xff08;FIFO&#xff09;的原则管理元素。在 Java 中&#xff0c;队列通常是通过链表或数组实现的&#xff0c;不同的实现类在内部数据结构和操作上可能有所不同。 1.原理 1.数据结构&#xff1a;队列的基本数据结构…

【网站项目】学生选课系统小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

el-tree基础渲染

el-tree 每个节点左右布局鼠标经过接电视&#xff0c;左边文字变色&#xff0c;右边不变 <el-tree:data"list":props"defaultProps"default-expand-all:expand-on-click-node"false"><template #default"{ data }"><e…

个人劳保用品穿戴检测系统 安全帽、工服、面罩、防护手套、防护鞋、安全背带穿戴检测等

背景 在工业生产、医疗护理、消防救援等高风险领域&#xff0c;正确穿戴个人防护装备或劳保用品&#xff08;PPE&#xff1a;Personal Protective Equipment&#xff09;是保障人员安全的重要措施&#xff0c;如安全帽、反光衣、安全背带等。然而&#xff0c;现实中往往会出现…