Python - 深夜数据结构与算法之 高级字符串

目录

一.引言

二.经典算法实战

1.Longest-Common-Sub-Seq [1143]

2.Edit-Distance [72]

3.Longest-Palindromic-Str [5]

4.Distinct-Sub-Seq [115]

5.Regular-Exp-Match [10]

三.总结


一.引言

上一节介绍了字符串的基本操作,本文介绍字符串更复杂的一些操作,主要设计动态规划与字符串扩展。

二.经典算法实战

1.Longest-Common-Sub-Seq [1143]

最长公共子序列: https://leetcode.cn/problems/longest-common-subsequence/description/

◆ 题目分析

状态转移方程:

根据二维 DP Table 理解转移方程更轻松些。

◆ 动态规划

class Solution(object):
    def longestCommonSubsequence(self, text1, text2):
        """
        :type text1: str
        :type text2: str
        :rtype: int
        """
    
        m, n = len(text1), len(text2)

        dp = [[0] * (n + 1) for _ in range(m + 1)]

        for i in range(1, m + 1):
            c1 = text1[i - 1]
            for j in range(1, n + 1):
                c2 = text2[j - 1]
                if c1 == c2:
                    dp[i][j] = dp[i-1][j-1] + 1
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        
        return dp[-1][-1]

2.Edit-Distance [72]

编辑距离: https://leetcode.cn/problems/edit-distance/

◆ 题目分析

和上一题的 DP Table 类似,但是初始的边界条件有所不同,其次需要注意转换时需要计算三个位置的最小值。

◆ 动态规划

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        # w[i] = w[j] -> w[i][j] = w[i-1]w[j-1]
        # w[i] != w[j] -> w[i][j] = min(w[i-1][j-1] + 1, w[i-1][j] + 1, w[i][j-1] +1)

        M, N = len(word1), len(word2)

        # 状态空间
        dp = [[0] * (N + 1) for _ in range(M + 1)]

        # word1="" word2="xxxx" 则 word1 -> word2 需要变换4次, 同理可得另一种情况
        for i in range(M + 1):
            dp[i][0] = i
        for j in range(N + 1):
            dp[0][j] = j

        for i in range(1, M + 1):
            c1 = word1[i-1]
            for j in range(1, N + 1):
                c2 = word2[j-1]
                # 此时字符相等,该位置无需变换,所以二者相同
                if c1 == c2:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    # 此时字符不同,需要看三种方法那种转换最小
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1

        return dp[-1][-1]

3.Longest-Palindromic-Str [5]

最长回文子串: https://leetcode.cn/problems/longest-palindromic-substring/description/ 

◆ 题目分析

首先明确回文串的定义,同时明确如果 i 或者 ii 为回文串时,我们可以向左右两边扩散,如果相同即为回文串。

◆ 中心扩散

class Solution(object):

    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """

        # 中心扩散
        def palindrome(s, st, end):
            # 边界合法且左右相等则向两边扩散
            while st >= 0 and end < len(s) and s[st] == s[end]:
                st -= 1
                end += 1
            
            # 我们需要 st-end 最后多加减了一次实际是 st-1 end+1,所以需要回补
            return s[st+1: end]

        res = ""

        for i in range(len(s)):

            sub1 = palindrome(s, i, i)
            sub2 = palindrome(s, i, i + 1)

            if len(sub1) > len(res):
                res = sub1
            if len(sub2) > len(res):
                res = sub2
        
        return res

4.Distinct-Sub-Seq [115]

不同子序列: https://leetcode.cn/problems/distinct-subsequences

◆ 题目分析

- 确定 DP 定义: 

dp[i][j]:以 i-1 为结尾的 s 子序列中出现以 j-1 为结尾的 t 的个数为 dp[i][j]。

- 确定递推公式:

s[i-1] == t[j-1] - 此时 dp[i][j] 可以不考虑这两个位置,所以复用 dp[i-1][j-1];当然也可以考虑 dp[i-1][j] 的情况,即 s[i-1] 结尾子序列中出现以 j 结尾的 t 的个数,因为我们计算的是 s 中有多少个 t,不是 t 中有多少个 s,

- 初始状态

dp[i][0] 表示:以 i-1为结尾的 s 可以随便删除元素,出现空字符串的个数,所以 dp[i][0] = 1

dp[0][j] 表示:空字符串 s 可以随便删除元素,出现以 j-1 为结尾的字符串 t 的个数,dp[0][j] = 0

dp[0][0]: dp[0][0] 应该是 1,空字符串 s,可以删除 0 个元素,变成空字符串 t。

◆ 动态规划

class Solution:
    def numDistinct(self, s, t):
        m, n = len(s), len(t)

        dp = [[0]*(n+1) for _ in range(m+1)]

        for i in range(m+1):
            dp[i][0] = 1
        for j in range(1, n+1):
            dp[0][j] = 0
        
        for i in range(1, m+1):
            for j in range(1, n+1):
                if s[i-1] == t[j-1]:
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
                else:
                    dp[i][j] = dp[i - 1][j]
        
        return dp[-1][-1]

5.Regular-Exp-Match [10]

正则匹配: https://leetcode.cn/problems/regular-expression-matching/

◆ 题目分析

首先判断第一个字符是否相同:

- 此时要么 s[0] = p[0] 或者 s[0] 随意 且 p[0] = "."

如果第一个字符相同,则进行推进,分多种情况:

- 如果此时 p 长度大于 2 且第二位 为 "*",则进入 "x*" 的匹配逻辑:

- 不需要 x* 匹配,默认 x 为 0 位,则直接忽略 2 位 p -> s 不变,p 推进两位 p[:2]

- x* 匹配了一个,接着匹配 x,则 s 推进1为 s[1:],p 不动,因为还在匹配 x

- p 非 "x*" 的状态,则判断第一位是否匹配,匹配后 s、p 同步推进 [1:]

◆ 递归实现

class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """

        # 模式为空时 只能匹配空串
        if len(p) == 0:
            return len(s) == 0

        # s 第一个字符与 p第一个字符相等或者 p 第一个字符为 "."
        firstMatch = len(s) >= 1 and (s[0] == p[0] or p[0] == '.')
 
        if len(p) >= 2 and p[1] == '*':
            # 0 * Char 的忽略情况 与 消除一个前面的字符继续保留该通配符
            return self.isMatch(s, p[2:]) or (firstMatch and self.isMatch(s[1:], p))
        
        # 硬匹配后同步推进
        return firstMatch and self.isMatch(s[1:], p[1:])

超时了,因为第二步 "x*" 会出现重复多次的情况。

◆ 递归 + Cache

class Solution(object):

    def __init__(self):
        self.cache = {}

    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """

        def DFS(i, j):

            if (i, j) in self.cache:
                return self.cache[(i, j)]
            # 模式为空时 只能匹配空串
            # if len(p) == 0:
            #   return len(s) == 0
            if j == len(p):
                return i == len(s)

            # # s 第一个字符与 p第一个字符相等或者 p 第一个字符为 "."
            # firstMatch = len(s) >= 1 and (s[0] == p[0] or p[0] == '.')
            firstMatch = i < len(s) and (s[i] == p[j] or p[j] == ".")
 
            # if len(p) >= 2 and p[1] == '*':
            if j + 1 < len(p) and p[j+1] == "*":
                # 0 * Char 的忽略情况 与 消除一个前面的字符继续保留该通配符
                # self.isMatch(s, p[2:]) or (firstMatch and self.isMatch(s[1:], p))
                re = DFS(i, j+2) or (firstMatch and DFS(i+1, j))
                self.cache[(i, j)] = re
                return re

            # 硬匹配后同步推进
            # return firstMatch and self.isMatch(s[1:], p[1:])
            re = firstMatch and DFS(i+1, j+1)
            self.cache[(i, j)] = re
            return re
        
        return DFS(0, 0)

把上面的代码转换为 DFS 并添加 cache,大家可以对照着之前的代码转换下。

三.总结

高级字符串的题目一般需要用到动态规划的方法,我们可以构建 DP Table,dp[i][j] 转移需要左上的三个位置的信息,根据题目的不同,做相应的取舍。

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

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

相关文章

YOLOv8改进 | 主干篇 | 低照度图像增强网络SCINet改进黑暗目标检测(全网独家首发)

一、本文介绍 本文给大家带来的改进机制是低照度图像增强网络SCINet,SCINet(自校正照明网络)是一种专为低光照图像增强设计的框架。它通过级联照明学习过程和权重共享机制来处理图像,优化了照明部分以提升图像质量。我将该网络集成在YOLOv8的主干上针对于图像的输入进行增…

BurpSuite Pro 2023.12.1.2下载与破解-最新版BurpSuite Pro

本文在我的博客地址是&#xff1a;https://h4cker.zip/post/f05ae2e66da503f6383dffe48cdf5bac 上一次BurpSuite的分享还是在2020年 由于CSDN有防盗链&#xff0c;我自己的博客都无法访问这篇博文的图片了 至于为什么再写一次&#xff0c;是因为我看到群里这张图&#xff1a;…

高效能方法 - 任务清单优先级

任务清单是有优先级的&#xff0c;首先要尽所能保证A级别的事项完成&#xff0c;或许不能估计B级或者C级&#xff0c;那这结果也是不错的。 博恩崔西在《吃掉那只青蛙》一书中指出&#xff1a;在你决定要做什么&#xff0c;并对其进行排序的时候&#xff0c;你首要解决那些最难…

腾讯云服务器价格查询,2024更新

腾讯云服务器租用优惠价格表&#xff1a;轻量应用服务器2核2G3M价格62元一年、2核2G4M价格118元一年&#xff0c;540元三年、2核4G5M带宽218元一年&#xff0c;2核4G5M带宽756元三年、轻量4核8G12M服务器646元15个月&#xff1b;云服务器CVM S5实例2核2G配置280.8元一年、2核4G…

x-cmd pkg | yq - 命令行 YAML处理工具

目录 简介首次用户支持格式转换友好的显示和操作语法与 jq 类似竞品和相关作品进一步阅读 简介 yq (YAML Query) 是一个轻量级的 YAML、JSON、XML 处理器&#xff0c;主要用于查询和提取 YAML 数据。 本 yq 的包来自 mikefarah/yq 项目&#xff0c;语法类似于 jq 。相比 kisly…

《WebKit 技术内幕》之八(2):硬件加速机制

2 Chromium的硬件加速机制 2.1 GraphicsLayer的支持 GraphicsLayer对象是对一个渲染后端存储中某一层的抽象&#xff0c;同众多其他WebKit所定义的抽象类一样&#xff0c;在WebKit移植中&#xff0c;它还需要具体的实现类来支持该类所要提供的功能。为了完成这一功能&#x…

python if条件判断的基础及应用

当前版本&#xff1a; Python 3.8.4 简介 if 语句是一种用于根据一个或多个条件的结果来执行不同代码块的控制流结构&#xff0c;它会检查给定的条件是否为真。如果条件为真&#xff0c;则执行与之关联的代码块&#xff1b;如果条件为假&#xff0c;则执行与之关联的其他代码块…

工作小计- RGB相关算子实现

项目中的模型一直都是直接操作NV12的yuv格式数据&#xff0c;这次的模型只支持RGB格式的输入&#xff0c;正好来自己实现对应的算子。 这里记录一下对应算子的实现过程&#xff0c;主要涉及到NV12到RGB的变换&#xff0c;RGB的crop/resize操作&#xff0c;对于数据的Norm/ToFlo…

python 正则表达式学习(1)

正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的检查一个字符串是否与某种模式匹配。 1. 特殊符号 1.1 符号含义 模式描述^匹配字符串的开头$匹配字符串的末尾.匹配任意字符&#xff0c;除了换行符&#xff0c;当re.DOTALL标记被指定时&#xff0c;则可以匹配包…

芯片工程系列(1)封装基础知识、分来、步骤与方法.md

英文缩写 环氧树脂模塑料&#xff08;Epoxy Molding Compound&#xff0c;EMC&#xff09;引线框架封装&#xff08;Leadframe&#xff09;&#xff0c;基板封装&#xff08;Substrate&#xff09;&#xff0c;Substrate 基板晶圆片级芯片规模封装&#xff08;Wafer Level Chi…

ESP32-UDP通信 (Arduino)

ESP32配置UDP通信 介绍 用户数据报协议UDP UDP&#xff08;User Datagram Protocol&#xff09;是一种在计算机网络中常用的传输层协议&#xff0c;它与TCP&#xff08;Transmission Control Protocol&#xff09;一样属于传输层协议的一种。UDP主要用于在网络中传输数据&…

小程序学习-20

建议每次构建npm之前都先删除miniprogram_npm

第15届蓝桥杯嵌入式省赛准备第三天总结笔记(使用STM32cubeMX创建hal库工程+串口接收发送)

因为我是自己搞得板子&#xff0c;原本的下程序和串口1有问题&#xff0c;所以我用的是串口2&#xff0c;用的PA2和PA3 一&#xff0c;使用CubeMX配置串口 选择A开头的这个是异步通信。 配置串口参数&#xff0c;往届的题基本用的9600波特率&#xff0c;所以我这里设置为9600…

【Linux】解决能访问github但克隆不了的问题

文章目录 1.查看你的代理的地址&#xff1a;2.git设置3.尝试clone 1.查看你的代理的地址&#xff1a; 2.git设置 先看看当前的git设置 $ git config --list然后git中要设置好对应的地址 git config --global http.proxy 127.0.0.1:78903.尝试clone $ git clone https://git…

异或运算的骚操作,由浅入深拿捏一类型的题

文章目录 &#x1f680;前言&#x1f680;异或运算的基本用法&#x1f680;一组数中一种数出现了奇数次&#xff0c;其他种数出现了偶数次&#xff0c;找出这个数&#x1f680;一组数中有两种数出现了奇数次&#xff0c;其他种数出现了偶数次&#xff0c;求这两个数✈️得到一个…

4D毫米波雷达——FFT-RadNet 目标检测与可行驶区域分割 CVPR2022

前言 本文介绍使用4D毫米波雷达&#xff0c;实现目标检测与可行驶区域分割&#xff0c;它是来自CVPR2022的。 会讲解论文整体思路、输入数据分析、模型框架、设计理念、损失函数等&#xff0c;还有结合代码进行分析。 论文地址&#xff1a;Raw High-Definition Radar for Mu…

[pytorch] 2. tensorboard

tensorboard简介 TensorBoard 是一组用于数据可视化的工具。它包含在流行的开源机器学习库 Tensorflow 中.但是也可以独立安装&#xff0c;服务Pytorch等其他的框架 可以常常用来观察训练过程中每一阶段如何输出的 安装pip install tensorboard启动tensorboard --logdir<d…

自定义注解与拦截器实现不规范sql拦截(自定义注解填充插件篇)

在自定义注解与拦截器实现不规范sql拦截&#xff08;拦截器实现篇&#xff09;中提到过&#xff0c;写了一个idea插件来辅助对Mapper接口中的方法添加自定义注解&#xff0c;这边记录一下插件的实现。 需求简介 在上一篇中&#xff0c;定义了一个自定义注解对需要经过where判…

理解PCIE设备透传

PCIE设备透传解决的是使虚拟机直接访问PCIE设备的技术&#xff0c;通常情况下&#xff0c;为了使虚拟机能够访问Hypervisor上的资源&#xff0c;QEMU&#xff0c;KVMTOOL等虚拟机工具提供了"trap and emulate"&#xff0c; Virtio半虚拟化等机制实现。但是这些实现都…

[学习笔记]刘知远团队大模型技术与交叉应用L4-Prompt-learning Delta-learning

Prompt-Learning and Delta-Tunning 背景和概览 但是从T5开始&#xff0c;大模型越来越大了。 微调很难了。 模型的趋势 Model Scaling&#xff1a;模型越来越大 Difficult Tuning&#xff1a;微调越来越难 Prompt-Learning 基本组成与流程介绍 预训练和fine-tuning有一…