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 // money
        n = n % money
    return m, n

print(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 = 0
    for i, (price, weight) in enumerate(goods):
        if w >= weight:
            m[i] = 1
            w -= weight
            total_v += price
        else:
            m[i] = w/weight
            total_v += m[i] * price
            w = 0
            break
    return m, total_v


print(fractional_backpack(goods, 50))

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

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

  • 例:32、94、128、1286、6、71可以拼接的最大整数为:94716321286128
from functools import cmp_to_key

li = [32, 94, 128, 1286, 6, 71]

def xy_cmp(x, y):
    if x+y > y+x:
        return -1
    elif x+y < y+x:
        return 1
    else:
        return 0

def 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 res

print(activity_selection(activities))

动态规划

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

思想:

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

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

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

例一:斐波那契数列

# 子问题的重复计算
def fibnacci(n):
    if n == 1 or n == 2:
        return 1
    else:
        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 0
    else:
        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 res


def cut_rod_recurision_2(p, n):
    if n == 0:
        return 0
    else:
        res = 0
        for i in range(1, n+1):
            res = max(res, p[i] + cut_rod_recurision_2(p, n-i))
    return res

print(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 = 0
        for 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 = j
        r.append(res_r)
        s.append(res_s)
    return r[n], s

def cut_rod_solution(p, n):
    r, s = cut_rod_extend(p, n)
    ans = []
    while n > 0:
        ans.append(s[n])
        n -= s[n]
    return ans

print(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))

 

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

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

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

相关文章

qemu源码解析(基于qemu9.0.0)

简介 QEMU是一个开源的虚拟化软件&#xff0c;它能够模拟各种硬件设备&#xff0c;支持多种虚拟化技术&#xff0c;如TCG、Xen、KVM等 TCG 是 QEMU 中的一个组件&#xff0c;它可以将高级语言编写的代码&#xff08;例如 C 代码&#xff09;转换为可在虚拟机中执行的低级代码…

InternlM2

第一次作业 基础作业 进阶作业 1. hugging face下载 2. 部署 首先&#xff0c;从github上git clone仓库 https://github.com/InternLM/InternLM-XComposer.git然后里面的指引安装环境

Day21_学点儿JavaEE__过滤器Filter(登录验证、编码处理)

1 为什么要使用过滤器 昨天已经总结过 当然&#xff0c;这仅仅是完成了一个简单的登录过程&#xff0c;即完成判断输入信息是否和数据库信息相匹配的操作&#xff0c;但是仍然可以通过直接输入地址的方式&#xff0c;在不登录的情况下访问相应的页面。而我们实际生活中的没登录…

ASUS华硕ROG幻16Air笔记本电脑GU605M原装出厂Win11系统工厂包下载,带有ASUSRecovery一键重置还原

适用型号&#xff1a;GU605MI、GU605MY、GU605MZ、GU605MV、GU605MU 链接&#xff1a;https://pan.baidu.com/s/1YBmZZbTKpIu883jYCS9KfA?pwd9jd4 提取码&#xff1a;9jd4 华硕原厂Windows11系统带有ASUS RECOVERY恢复功能、自带所有驱动、出厂主题壁纸、系统属性联机支持…

谷歌查问题

1&#xff0c;打开 it工具箱-里面啥都有 2&#xff0c;找到谷歌 3&#xff0c;访问gpt

跟TED演讲学英文:The next grand challenge for AI by Jim Fan

The next grand challenge for AI Link: https://www.ted.com/talks/jim_fan_the_next_grand_challenge_for_ai? Speaker: Jim Fan Date: October 2023 文章目录 The next grand challenge for AIIntroductionVocabularyTranscriptSummary后记 Introduction Researcher Jim…

深入理解MD5算法:原理、应用与安全

title: 深入理解MD5算法&#xff1a;原理、应用与安全 date: 2024/4/11 20:55:57 updated: 2024/4/11 20:55:57 tags: MD5算法数据安全哈希函数摘要算法安全漏洞SHA算法密码学 第一章&#xff1a;引言 导言 在当今数字化时代&#xff0c;数据安全和完整性变得至关重要。消息…

PHP婚恋小程序开发源码支持微信+公众号+APP

随着社会的发展和人们生活节奏的加快&#xff0c;传统的相亲方式已经不能满足现代人的需求。在此背景下&#xff0c;有人想到通过线上小程序的方式来满足更多的人进行相亲&#xff0c;所以在此情况下&#xff0c;婚恋相亲小程序由此出现。婚恋相亲小程序的功能有会员功能&#…

Postman接口测试工具

Postman接口测试工具 目录 Postman接口测试工具安装页面概述保存任务发送请求 安装 PostMan官方下载网址&#xff1a;https://www.getpostman.com/downloads/ 页面概述 保存任务 新建请求集合 命名为test 将刚刚的任务保存 选择新建的test集合 发送请求 新建窗口 request请…

解决源 “MySQL 8.0 Community Server“ 的 GPG 密钥已安装,但是不适用于此软件包。请检查源的公钥 URL 是否配置正确。

源 “MySQL 8.0 Community Server” 的 GPG 密钥已安装&#xff0c;但是不适用于此软件包。请检查源的公钥 URL 是否配置正确。 失败的软件包是&#xff1a;mysql-community-server-8.0.31-1.el7.x86_64 GPG 密钥配置为&#xff1a;file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql…

vue源码解析——v-if和v-for哪个优先级高,如何避免两者同时使用

首先&#xff0c;官方不推荐v-if和v-for在同一个元素上使用。其次&#xff0c;如果两者同时使用&#xff0c;v-if和v-for的优先级怎么确定&#xff1f;在vue2和vue3中这两者的优先级顺序不一样。vue2是v-for优先&#xff0c;条件不存在时也会渲染多个注释节点。在vue3中进行了改…

JVM 垃圾收集器

JVM 垃圾收集器 垃圾收集器 垃圾收集器 Serial (串行)&#xff1a;单线程垃圾回收器&#xff1b;采用复制算法 Serial Old&#xff1a;Serial 收集器的老年代版本&#xff0c;采用标记-整理算法。 ParNew&#xff1a;多线程的垃圾回收器&#xff08;Serial 的多线程版本&#x…

推荐一个大学生可以参加的榜单赛事|人工智能赛道

【榜单赛事】第十四届全国大学生计算机应用能力与数字素养大赛 - 人工智能产业应用赛道人工智能编程赛项 正在火热报名中 本赛道定位于人工智能产业应用和实践&#xff0c;把人工智能产业真实的技能要求、能力要求体现在竞赛内容设计当中&#xff0c;并在竞赛环节融入实战项目…

SQLite Android 绑定(十八)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite 在Android安装与定制方案&#xff08;十七&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 ​ 应用程序编程 加载共享库 在使用任何与 SQLite 相关的方法或对象之前&#xff0c;本机 SQLite 必…

H5:canvas刮刮乐

今日无事&#xff0c;写一个刮刮乐用于收割亲弟弟零花钱 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>Title</title><style>body {height: 100vh;background-color: #fff;}.textDiv {…

数学之光照亮AI之路:探究数学背景在人工智能学习中的优势

在科技日新月异的今天&#xff0c;人工智能&#xff08;AI&#xff09;已成为引领未来发展的重要力量。然而&#xff0c;对于许多初涉此领域的学习者来说&#xff0c;AI的复杂性和深度常常让他们望而却步。有趣的是&#xff0c;那些数学基础扎实的人在学习AI时&#xff0c;往往…

2024 Android Studio安装及配置gradle快速省心搭建,不放C盘,前置搭建

题外话&#xff1a;要做安卓项目然后安装过Android Studio的朋友都知道&#xff0c;下载安装完成之后并不能直接开始你的第一个安卓项目的“ Hello World”&#xff0c;其中有要配置好gradle&#xff0c;在你测试好环境之前你会遇到很多问题&#xff0c;同时默认下使用中所需依…

Redis从入门到精通(十二)Redis实战(九)GEO查询附近商户、BitMap用户签到和统计、HLL的UV统计

↑↑↑请在文章开头处下载测试项目源代码↑↑↑ 文章目录 前言4.10 附近商户4.10.1 GEO介绍4.10.2 附近商户需求分析4.10.3 实现新增商户功能4.10.4 实现查询附近商户功能 4.11 用户签到4.11.1 用户签到需求分析4.11.2 BitMap介绍4.11.3 实现用户签到4.11.4 实现用户签到统计4.…

备战蓝桥杯---数学刷题3

话不多说&#xff0c;直接看题&#xff1a; 1. 我们可以得到大致一个思路&#xff0c;就是先枚举1-1e6的质数&#xff0c;然后看看有几个即可。 我们怎么知道个数呢&#xff1f; 首先我们知道1---n中有n/p的下取整个为p的倍数。 因此&#xff0c;p的个数至少是n/p的下取整个…

损失函数-交叉熵 梯度下降

文章目录 1、交叉熵的简单例子1.2、Classification Error&#xff08;分类错误率&#xff09;1.3、Mean Squared Error (均方误差)1.4、交叉熵损失函数1.5、二分类 2、什么是梯度下降法&#xff1f;2.2、梯度下降法的运行过程2.3、二元函数的梯度下降 1、交叉熵的简单例子 参考…