【算法进阶2-动态规划】最长公共子序列、欧几里得算法-分数、RSA算法-密码于加密

news2024/11/16 5:45:18

1 最长公共子序列
2 欧几里得算法
2.1 欧几里得算法-分数
3 RSA算法-密码于加密

1 最长公共子序列

在这里插入图片描述

-个序列的子序列是在该序列中删去若干元素后得 到的序列。
例:“ABCD”和“BDF”都是“ABCDEFG”的子序列

最长公共子序列(LCS)问题:给定两个序列X和Y,求X和Y长度最大的公共子序列。
例:X="ABBCBDE" Y="DBBCDB" LCS(X,Y)="BBCD"

应用场景:字符串相似度比对

在这里插入图片描述

from typing import Tuple


def lcs_length(x: str, y: str) -> int:
    """
    计算两个字符串的最长公共子序列 (LCS) 的长度。

    使用动态规划方法解决LCS问题。LCS问题是指在两个字符串中找到一个最长的子序列,
    使得这个子序列在两个字符串中都出现,并且保持其相对顺序不变。

    :param x: 第一个字符串
    :param y: 第二个字符串
    :return: 返回两个字符串的最长公共子序列的长度
    """
    m = len(x)  # 第一个字符串的长度
    n = len(y)  # 第二个字符串的长度

    # 创建一个 (m+1) x (n+1) 的二维列表 c,用于存储子问题的解
    # c[i][j] 表示字符串 x 的前 i 个字符和字符串 y 的前 j 个字符的最长公共子序列的长度
    c = [[0 for _ in range(n + 1)] for _ in range(m + 1)]

    # 填充二维列表 c
    for i in range(1, m + 1):  # 遍历字符串 x 的每个字符
        for j in range(1, n + 1):  # 遍历字符串 y 的每个字符
            if x[i - 1] == y[j - 1]:  # 如果 x 的第 i 个字符等于 y 的第 j 个字符
                # 如果字符匹配,当前最长公共子序列的长度是左上角的值 + 1
                c[i][j] = c[i - 1][j - 1] + 1
            else:
                # 如果字符不匹配,取上方或左方的最大值
                c[i][j] = max(c[i - 1][j], c[i][j - 1])

    # 打印二维列表 c 的值(用于调试)
    for _ in c:
        print('列表的值是:', _)

    # 返回最长公共子序列的长度,即 c[m][n]
    return c[m][n]


# print(lcs_length("ABCBDAB", "BDCABA"))  # 4

# 列表的值是: [0, 0, 0, 0, 0, 0, 0]
# 列表的值是: [0, 0, 0, 0, 1, 1, 1]
# 列表的值是: [0, 1, 1, 1, 1, 2, 2]
# 列表的值是: [0, 1, 1, 2, 2, 2, 2]
# 列表的值是: [0, 1, 1, 2, 2, 3, 3]
# 列表的值是: [0, 1, 2, 2, 2, 3, 3]
# 列表的值是: [0, 1, 2, 2, 3, 3, 4]
# 列表的值是: [0, 1, 2, 2, 3, 4, 4]

def lcs(x: str, y: str) -> Tuple[int, list]:
    """
    计算两个字符串的最长公共子序列 (LCS) 的长度,并生成动态规划表。

    使用动态规划方法求解两个字符串的最长公共子序列问题,并返回
    长度以及记录方向的表,用于后续的LCS路径恢复。

    :param x: 第一个字符串
    :param y: 第二个字符串
    :return: 返回一个元组,包含两个元素:
             - LCS的长度
             - 动态规划表 b,其中 b[i][j] 表示到达位置 (i, j) 时的方向
    """
    m = len(x)  # 第一个字符串的长度
    n = len(y)  # 第二个字符串的长度

    # 创建一个 (m+1) x (n+1) 的二维列表 c,用于存储子问题的解
    # c[i][j] 表示字符串 x 的前 i 个字符和字符串 y 的前 j 个字符的最长公共子序列的长度
    c = [[0 for _ in range(n + 1)] for _ in range(m + 1)]

    # 创建一个 (m+1) x (n+1) 的二维列表 b,用于记录方向
    # b[i][j] 表示到达位置 (i, j) 时的方向
    # "←" 表示来自左上方(匹配),
    # "↑" 表示来自上方(不匹配,向上移动),
    # "↖" 表示来自左方(不匹配,向左移动)
    b = [['*' for _ in range(n + 1)] for _ in range(m + 1)]

    # 填充二维列表 c 和 b
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if x[i - 1] == y[j - 1]:  # 如果 x 的第 i 个字符等于 y 的第 j 个字符
                # 如果字符匹配,当前最长公共子序列的长度是左上角的值 + 1
                c[i][j] = c[i - 1][j - 1] + 1
                b[i][j] = "←"  # 方向来自于左上方(匹配)
            elif c[i - 1][j] > c[i][j - 1]:  # 如果来自上方的值大于来自左方的值
                # 如果上方的值更大,选择上方的值
                c[i][j] = c[i - 1][j]
                b[i][j] = "↑"  # 方向来自于上方(不匹配,向上移动)
            else:
                # 如果左方的值更大或相等,选择左方的值
                c[i][j] = c[i][j - 1]
                b[i][j] = "↖"  # 方向来自于左方(不匹配,向左移动)

    # 返回最长公共子序列的长度和方向记录表
    return c[m][n], b


c, b = lcs("ABCBDAB", "BDCABA")
for _ in b:
    print(_)

# ['*', '*', '*', '*', '*', '*', '*']
# ['*', '↖', '↖', '↖', '←', '↖', '←']
# ['*', '←', '↖', '↖', '↖', '←', '↖']
# ['*', '↑', '↖', '←', '↖', '↖', '↖']
# ['*', '←', '↖', '↑', '↖', '←', '↖']
# ['*', '↑', '←', '↖', '↖', '↑', '↖']
# ['*', '↑', '↑', '↖', '←', '↖', '←']
# ['*', '←', '↑', '↖', '↑', '←', '↖']


def lcs_traceback(x: str, y: str) -> str:
    """
    根据动态规划表回溯,找出两个字符串的最长公共子序列 (LCS)。

    使用动态规划表 `b` 来回溯最长公共子序列的路径,并从结果表 `c` 中
    获取最长公共子序列的字符。最终返回最长公共子序列的字符串。

    :param x: 第一个字符串
    :param y: 第二个字符串
    :return: 返回两个字符串的最长公共子序列(LCS)的字符串表示
    """
    # 调用 lcs 函数获取动态规划表 c 和方向记录表 b
    c, b = lcs(x, y)

    i = len(x)  # 初始化 i 为第一个字符串的长度
    j = len(y)  # 初始化 j 为第二个字符串的长度

    res = []  # 用于存储回溯得到的 LCS 字符

    # 根据方向记录表 b 从表的右下角开始回溯到左上角
    while i > 0 and j > 0:
        if b[i][j] == "←":
            # 如果方向来自于左上方(匹配),则当前字符是 LCS 的一部分
            res.append(x[i - 1])
            i -= 1  # 移动到前一个字符
            j -= 1  # 移动到前一个字符
        elif b[i][j] == "↑":
            # 如果方向来自于上方,则移动到上方的子问题
            i -= 1
        else:  # '↖'
            # 如果方向来自于左方,则移动到左方的子问题
            j -= 1

    # 由于回溯过程中字符是从 LCS 的末尾开始添加的,所以需要反转结果列表
    return "".join(res[::-1])


print(lcs_traceback("ABCBDAB", "BDCABA"))  # BDAB

2 欧几里得算法

在这里插入图片描述
在这里插入图片描述

def gcd(a: int, b: int) -> int:
    """
    递归求解两个数的最大公约数 (GCD)。

    使用欧几里得算法通过递归的方式计算两个整数的最大公约数。
    当第二个数 b 为 0 时,最大公约数是第一个数 a。

    :param a: 第一个整数
    :param b: 第二个整数
    :return: 返回 a 和 b 的最大公约数
    """
    if b == 0:
        return a  # 基本情况:当 b 为 0 时,a 是最大公约数
    else:
        # 递归调用:计算 b 和 a % b 的最大公约数
        return gcd(b, a % b)


print(gcd(12, 16))  # 4


def gcd2(a: int, b: int) -> int:
    """
    非递归求解两个数的最大公约数 (GCD)。

    使用欧几里得算法通过迭代的方式计算两个整数的最大公约数。
    通过不断更新 a 和 b 直到 b 为 0,此时 a 就是最大公约数。

    :param a: 第一个整数
    :param b: 第二个整数
    :return: 返回 a 和 b 的最大公约数
    """
    while b > 0:
        r = a % b  # 计算 a 除以 b 的余数
        a = b  # 更新 a 为 b
        b = r  # 更新 b 为余数
    return a  # 当 b 为 0 时,a 是最大公约数


print(gcd2(12, 16))  # 4

2.1 动态规划之欧几里得算法-分数

class Fraction:
    def __init__(self, a: int, b: int):
        """
        初始化一个分数对象,并将其化简为最简分数。

        :param a: 分子
        :param b: 分母
        """
        self.a = a
        self.b = b

        # 计算最大公约数
        x = self.gcd(a, b)

        # 将分子和分母除以最大公约数,化简为最简分数
        self.a /= x
        self.b /= x

    @staticmethod
    def gcd(a: int, b: int) -> int:
        """
        非递归求解两个数的最大公约数 (GCD)。

        使用欧几里得算法通过迭代的方式计算两个整数的最大公约数。
        通过不断更新 a 和 b 直到 b 为 0,此时 a 就是最大公约数。

        :param a: 第一个整数
        :param b: 第二个整数
        :return: 返回 a 和 b 的最大公约数
        """
        while b > 0:
            r = a % b  # 计算 a 除以 b 的余数
            a = b  # 更新 a 为 b
            b = r  # 更新 b 为余数
        return a  # 当 b 为 0 时,a 是最大公约数

    def __str__(self) -> str:
        """
        返回分数的字符串表示形式。

        :return: 返回分数的字符串表示,例如 "3/4"
        """
        return f"{int(self.a)}/{int(self.b)}"

    @staticmethod
    def zgs(a: int, b: int) -> int:
        """
        计算两个数的最小公倍数 (Least Common Multiple, LCM)。

        使用公式 LCM(a, b) = abs(a * b) / GCD(a, b) 来计算最小公倍数。

        :param a: 第一个整数
        :param b: 第二个整数
        :return: 返回 a 和 b 的最小公倍数,类型为整数
        """
        x = Fraction.gcd(a, b)  # 调用静态方法 gcd 计算最大公约数
        return a * b // x  # 根据公式计算最小公倍数,使用整数除法返回整数结果

    def __add__(self, other: 'Fraction') -> 'Fraction':
        # 3/5 + 2/7
        """
        重载加法运算符,实现两个分数相加。

        通过计算两个分数的最小公倍数来统一分母,并计算新分数的分子。

        :param self: 第一个分数对象
        :param other: 第二个分数对象
        :return: 返回两个分数相加后的结果,作为新的 Fraction 对象
        """
        a = self.a  # 当前分数的分子
        b = self.b  # 当前分数的分母
        c = other.a  # 另一个分数的分子
        d = other.b  # 另一个分数的分母

        denominator = self.zgs(b, d)  # 计算两个分数分母的最小公倍数
        numerator = a * denominator // b + c * denominator // d  # 计算新分数的分子,使用整数除法确保结果为整数

        return Fraction(int(numerator), int(denominator))  # 返回新的 Fraction 对象,表示两个分数相加的结果


# f = Fraction(30, 16)
# print(f)  # 输出 15/8

a = Fraction(3, 4)
b = Fraction(1, 2)
print(a + b)  # 5/6

3 RSA算法-密码于加密

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

请你谈谈:async与await是如何控制异步操作的执行顺序

async/await 是 JavaScript 中用于处理异步操作的一种语法糖,它使得异步代码的编写、阅读和维护变得更加容易和直观。async 和 await 关键字是在 ES2017(ES8)中引入的,旨在简化基于 Promise 的异步操作。 1 async async 是一个函…

Pytorch如何指定device(cuda or cpu)例子解析

代码示例: 在PyTorch中,指定设备(CPU或CUDA)是一个非常重要的步骤,特别是当你在进行深度学习训练时。以下是一些指定设备的详细例子: 检查CUDA是否可用: 首先,你需要检查你的机器是否支持CUDA&…

【C++ Primer Plus习题】5.9

问题: 解答: #include <iostream> #include <cstring> using namespace std;#define SIZE 20int main() {string words[SIZE];string done "done";int count 0;while (true){cout << "请输入单词:" << endl;cin >> words…

2054. 骑马修栅栏

代码 #include<bits/stdc.h> using namespace std; int mp[505][505]; queue<int> ans; int du[505]; int n0,m,u,v;void dfs(int i) {for(int j1;j<n;j){if(mp[i][j]>1){mp[i][j]--;mp[j][i]--;dfs(j);}}ans.push(i); } int main() {cin>>m;for(int …

javaSpringBootmysql的大学生心理健康管理系统39182-计算机毕业设计项目选题推荐(附源码)

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;高校当然也不例外。大学生心理健康管理系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c…

一文搞懂不确定性原理

在讲这个之前&#xff0c;我们先要搞清楚&#xff0c;什么是不确定性原理&#xff1f;然后再解释它为什么就是不确定的呢&#xff1f; 我还模糊记得我第一次接触这个东西的时候&#xff0c;是在高中物理教材上面提了一下。其中印象最深的就是&#xff1a;动量确定&#xff0c;…

记录|Steam登录不上,打开速度慢等问题

目录 前言一、方法1二、方法2&#xff1a;cmd指令三、steam账号可以多台电脑一起用吗&#xff1f;更新时间 前言 参考视频&#xff1a; Steam登不上&#xff1f;商店打不开&#xff1f;多种方案助你解决问题&#xff01; 一、方法1 打开Steam的快捷方式的“属性”&#xff0c;…

[ICLR-24] LRM: Large Reconstruction Model for Single Image to 3D

[pdf | proj | code] 本文首次提出大型重建模型&#xff08;Large Reconstruction Model, LRM&#xff09;&#xff0c;实现5s内对单图物体的3D重建。在128张A100&#xff08;40G&#xff09;上训练30 epochs。 LRM包含三个部分&#xff0c;具体框架如下&#xff1a; 图片编码…

[C++] 初识 智能指针

标题&#xff1a;[C] 初识 智能指针 水墨不写bug 目录 一、前言 二、智能指针 1. 什么是RAII&#xff1f; 2.智能指针分类 三、智能指针简介 1.std::auto_ptr 2.std::unique_ptr 3.std::shared_ptr 正文开始&#xff1a; 一、前言 C智能指针的出现是有一定的背景的&am…

shell程序设计入门(三)

shell程序设计入门&#xff08;三&#xff09; 导语命令简单命令break:命令continueechoevalexecexitexprprintfreturnshift 复杂指令.exportsetunsettrapfindgrep 总结参考文献 导语 本篇介绍一些shell中常用的复杂命令及其使用&#xff0c;如set、echo、expr等命令 命令 简…

【每日一题】【区间合并】【贪心 模拟】多米诺骨牌 牛客小白月赛99 E题 C++

牛客小白月赛99 E题 多米诺骨牌 题目背景 牛客小白月赛99 题目描述 样例 #1 样例输入 #1 3 6 1 1 1 1 3 2 1 4 3 2 7 9 11 6 2 1 1 1 3 2 1 4 3 2 7 9 11 5 4 1 4 1 1 2 1 2 3 6 8样例输出 #1 3 6 5做题思路 按照玩多米诺骨牌的方式。 先将多米诺骨牌按照骨牌位置从小…

ai伴学之“修图”

偶一张孩子专注的抓拍&#xff0c;通过与ai探讨修图心得让做图理念更完备。 (笔记模板由python脚本于2024年08月25日 18:23:49创建&#xff0c;本篇笔记适合喜欢搞图的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a…

JAVA_10

JAVA_10 JAVA异常机制及bug追踪1. 异常 JAVA异常机制及bug追踪 1. 异常 英文:Exception 所谓异常处理&#xff0c;就是指程序在出现问题时依然可以正确的执行完。Java面向对象处理异常过程 抛出异常:在执行一个方法时&#xff0c;如果发生异常&#xff0c;则这个方法生成代表…

Layer-refined Graph Convolutional Networks for Recommendation【ICDE2023】

Layer-refined Graph Convolutional Networks for Recommendation 论文&#xff1a;https://arxiv.org/abs/2207.11088 源码&#xff1a;https://github.com/enoche/MMRec/blob/master/README.md 摘要 基于图卷积网络&#xff08;GCN&#xff09;的抽象推荐模型综合了用户-项目…

Chainlit接入FastGpt接口完美对接,实现全新的用户聊天界面

前言 由于fastgpt只提供了一个分享用的网页应用&#xff0c;网页访问地址没法自定义&#xff0c;虽然可以接入NextWeb/ChatGPT web等开源应用。但是如果我们想直接给客户应用&#xff0c;还需要客户去设置配置&#xff0c;里面还有很多我们不想展示给客户的东西怎么办&#xf…

# 利刃出鞘_Tomcat 核心原理解析(九)-- Tomcat 安全

利刃出鞘_Tomcat 核心原理解析&#xff08;九&#xff09;-- Tomcat 安全 一、Tomcat专题 - Tomcat安全 - 配置安全 1、 删除 tomcat 的 webapps 目录下的所有文件&#xff0c;禁用 tomcat 管理界面. 如下目录均可删除&#xff1a; D:\java-test\apache-tomcat-8.5.42-wind…

轻松实现PDF转图片!2024四大实用工具推荐!

有时候我们需要将PDF文件中的内容转换为图片格式&#xff0c;以便在不同的平台和设备上更好地展示和分享。"PDF转图片"这一需求催生了众多转换工具的出现&#xff0c;它们以高效、便捷的服务帮助用户轻松实现格式转换。 福昕PDF转换大师&#xff08;365客户端&#…

JAVA Future类详解

在编程中&#xff0c;Java中的"Future"是一个接口&#xff0c;代表是作为主线程开辟的一个分支任务&#xff0c;处理耗时的业务&#xff0c;并且可以可以为主线程最终返回异步计算的结果。此外&#xff0c;它提供了检查计算是否完成&#xff0c;等待其完成&#xff0…

ISP 3A 算法:自动曝光(AE)中的平均亮度法详解

在自动曝光&#xff08;AE&#xff09;算法中&#xff0c;平均亮度法是一种经典且广泛应用的技术。它通过计算场景中所有像素的平均亮度来确定最佳曝光设置&#xff0c;从而保证图像的整体亮度处于适当的水平。尽管该方法相对简单&#xff0c;但它在AE算法中扮演着重要的角色&a…

仕考网:专科考公好考吗?有岗位吗?

2024年&#xff0c;国家公务员以及大多数省市的公务员考试接受至少拥有大专学历的考生。某些特定职位&#xff0c;例如上海市和北京市的岗位&#xff0c;可能要求考生必须持有本科或以上学历才能参与考试。 属于国家公务员考试、省直属单位、市直属单位以及中央直属单位的职位…