• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

python滑动窗口法及动态规划方法求解最长公共子串问题

互联网 diligentman 6天前 11次浏览

最长公共子串问题

题目:给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子字符串
一个字符串的子字符串是指从该字符串中截取的某个个连续片段。
例如,“abc” 是 “abcde” 的子字符串,但 “abd” 不是 “abcde” 的子字符串。两个字符串公共子字符串是这两个字符串共有的子字符串。

这个题目可以用两种方法来求解

滑动窗口法

为了了解求解的过程,我们先来看看下面几个图,可以清晰地看出滑动窗口解法是怎么求解的,看懂了图片求解的过程,之后的编程就很简单了,只是把图片上面的思维转化成程序的语言就行
python滑动窗口法及动态规划方法求解最长公共子串问题
有两个字符串sdfghasdfrtbnfghnad
我们来从图中看看滑动窗口方法是怎么工作的
python滑动窗口法及动态规划方法求解最长公共子串问题

  • 从图中可以看出解题的基本思路,剩下的就是把思路转化为代码
def get_longest_comment_sub_string(s1: str, s2: str):
    s1_len = len(s1)
    s2_len = len(s2)
    # 确定长字符串,短串
    (long_str, shot_str, max_len, min_len) = (s1, s2, s1_len, s2_len) if s1_len > s2_len else (s2, s1, s2_len, s1_len)
    # 记录最长子串长度
    max_count = 0
    # 记录最长子串
    sub_str = None
    # 记录匹配的长度
    match_count = 0
    # 窗口从长串开始滑动
    for i in range(max_len):
        # 计算长串剩余的长度
        left_len = max_len - i
        # 确定需要计数的长度,防止列表越界
        count_len = min(min_len, left_len)
        for j in range(count_len):
            if long_str[i + j] == shot_str[j]:
                match_count += 1
                if match_count > max_count:
                    # 记录长度
                    max_count = match_count
                    # 记录子串
                    sub_str = shot_str[j + 1- match_count : j + 1]
            else:
                # 记录归0
                match_count = 0
        # 这里要归0 很重要(如果这层循环尾部字符正好相同,不归0会出BUG)
        match_count = 0
    return sub_str

动态规划法

动态规划的方法我们也可以用画图的方式来理解这个过程
python滑动窗口法及动态规划方法求解最长公共子串问题

  • 从图中可以看出每次取出字符比较的时候如果字符相等,则该对应下标的数字等于其斜上方的数字+ 1
def dp_longest_comment_sub_string(s1: str, s2: str):
    n = len(s1)
    m = len(s2)
    # 构建(m+1)*(n+1)的0矩阵
    dp = [[0 for _ in range(m + 1)] for _ in range(n + 1)]
    # 记录最大长度
    max_count = 0
    # 记录最长子串
    sub_str = None
    for i in range(n):
        for j in range(m):
            if s1[i] == s2[j]:
                # 记录此时的子串长度等于斜上方+1
                dp[i + 1][j + 1] = dp[i][j] + 1
                # 和最长长度比较
                if dp[i + 1][j + 1] > max_count:
                    # 如果大于已知最长,则覆盖记录
                    max_count = dp[i + 1][j + 1]
                    sub_str = s1[i + 1 - max_count:i + 1]
    return sub_str

总结

动态规划的方法在代码结构上要优于滑动窗口的方法,但是滑动窗口的方法便于理解
两者的时间复杂度都是

O

(

m

n

)

O(m*n)

O(mn),,其中m,n为字符串长度
滑动窗口不需要开辟新的空间(记录子串不算在内),动态规划则需要开辟新的内存空间存储dp数组


喜欢 (0)