2024年春季学期《算法分析与设计》练习8

本文介绍了如何使用备忘录法和动态规划算法解决最长公共子序列问题,包括示例代码和输入输出解释。两篇问题分别涉及LCS的长度计算、构造最长公共子序列以及特定场景下的应用。
摘要由CSDN通过智能技术生成

问题 A: 最长公共子序列问题(LCS)之备忘录法

题目描述
使用备忘录法求解两个序列的最长公共子序列的长度。
输入
每组输入包括两行,每行包括一个字符串。
输出

两个序列的最长公共子序列的长度。

样例输入 Copy
ACBCDABD
ABDCABA

 

样例输出 Copy
5
def LCS(s1, s2, m, n, memo):
    # 边界条件
    if m == 0 or n == 0:
        return 0

    # 检查备忘录
    if (m, n) in memo:
        return memo[(m, n)]

    # 递归计算
    if s1[m-1] == s2[n-1]:
        memo[(m, n)] = 1 + LCS(s1, s2, m-1, n-1, memo)
    else:
        memo[(m, n)] = max(LCS(s1, s2, m-1, n, memo), LCS(s1, s2, m, n-1, memo))

    return memo[(m, n)]

while 1:
    s1 = input()
    s2 = input()
    memo = {}
    print(LCS(s1, s2, len(s1), len(s2), memo))

问题 B: 最长公共子序列问题(LCS)之动态规划法

题目描述

使用动态规划算法求解两个序列的最长公共子序列的长度。

输入

每组输入包括两行,每行包括一个字符串。

输出

两个序列的最长公共子序列的长度。

样例输入 Copy
ACBCDABD
ABDCABA
样例输出 Copy
5
def LCS(X, Y):
    len_X, len_Y = len(X), len(Y)
    # 初始化dp数组
    dp = [[0] * (len_Y + 1) for _ in range(len_X + 1)]

    # 填充dp数组
    for i in range(1, len_X + 1):
        for j in range(1, len_Y + 1):
            if X[i - 1] == Y[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

    # 返回最长公共子序列的长度
    return dp[len_X][len_Y]

while 1:
    X = input()
    Y = input()
    print(LCS(X, Y))

问题 C: 最长公共子序列问题(LCS)-构造LCS

 

题目描述

使用动态规划算法求两个序列的最长公共子序列,需构造一条最长公共子序列。

输入

每组输入包括两行,每行包括一个字符串。

输出

两个字符序列的一条最长公共子序列。(输入已确保最长公共子序列的唯一性)

样例输入 Copy
acdbxx
ccdxx
样例输出 Copy
cdxx
def LCS(X, Y):
    len_X, len_Y = len(X), len(Y)
    # 初始化DP表
    dp = [["" for _ in range(len_Y + 1)] for _ in range(len_X + 1)]

    # 填充DP表
    for i in range(1, len_X + 1):
        for j in range(1, len_Y + 1):
            if X[i - 1] == Y[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + X[i - 1]
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1], key=len)

    # 回溯找到最长公共子序列
    lcs = ""
    i, j = len_X, len_Y
    while i > 0 and j > 0:
        if X[i - 1] == Y[j - 1]:
            lcs = X[i - 1] + lcs
            i -= 1
            j -= 1
        elif len(dp[i - 1][j]) > len(dp[i][j - 1]):
            i -= 1
        else:
            j -= 1

    return lcs

while 1:
    X = input()
    Y = input()
    print(LCS(X, Y))

问题 D: 牛牛的字符串

题目描述

牛牛有两个字符串(可能包含空格),他想找出其中最长的公共连续子串的长度,希望你能帮助他。例如:两个字符串分别为"abede"和"abgde",结果为2。

输入

每组数据包括两行,每行为一个字符串。

输出

输出最长的公共连续子串的长度。

样例输入 Copy
abede
abgde
样例输出 Copy
2
def longest_common_substring(str1, str2):
    len_str1, len_str2 = len(str1), len(str2)
    # 初始化DP表
    dp = [[0] * (len_str2 + 1) for _ in range(len_str1 + 1)]
    max_length = 0  # 记录最长公共子串的长度

    # 填充DP表
    for i in range(1, len_str1 + 1):
        for j in range(1, len_str2 + 1):
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
                max_length = max(max_length, dp[i][j])
            else:
                dp[i][j] = 0

    return max_length

while 1:
    str1 = input()
    str2 = input()
    print(longest_common_substring(str1, str2))

问题 E: 最大子段和

题目描述

给定n个整数(可能是负数)组成的序列a[1], a[2], a[3], …, a[n],求该序列的子段和如a[i]+a[i+1]+…+a[j]的最大值。

输入

每组输入包括两行,第一行为序列长度n,第二行为序列。

输出

输出字段和的最大值。

样例输入 Copy
5
-1 0 1 2 3
样例输出 Copy
6
def max_subarray_sum(a):
    n = len(a)
    # 初始化dp数组
    dp = [0] * n
    dp[0] = a[0]
    max_sum = dp[0]  # 记录最大子段和

    # 填充dp数组
    for i in range(1, n):
        dp[i] = max(dp[i - 1] + a[i], a[i])
        max_sum = max(max_sum, dp[i])

    return max_sum

while 1:
    n = int(input())
    a = list(map(int, input().split()))
    print(max_subarray_sum(a))

问题 F: 最大子段和升级版

题目描述

使用动态规划算法求整数数组(可能包含负整数)的最大子段和,以及和最大子段的起始位置和结束位置:
例如:输入数组(6,-1,5,4,-7),输出14, 1, 4,其中14表示最大子段和,1表示和最大的子段从第1个数字开始,4表示和最大的子段到第4个数字结束,即(6, -1 , 5, 4)。

输入

每组输入两行,第1行为数组中包含的整数个数n,第2行为n个整数(可能包含负整数),两两之间用空格隔开。

输出

输出最大子段和,以及和最大子段的起始位置和结束位置,两两之间用空格隔开。

样例输入 Copy
5
6 -1 5 4 -7
样例输出 Copy
14 1 4
def solve(a, n):
    b = [0] * n
    b[0] = a[0]
    max_sum = b[0]
    start = end = 0

    for i in range(1, n):
        if b[i - 1] > 0:
            b[i] = b[i - 1] + a[i]
        else:
            b[i] = a[i]
        if max_sum < b[i]:
            max_sum = b[i]
            end = i

    # 找到最大子段和的起始位置
    j = end
    while b[j] > 0 and j >= 0:
        j -= 1
    start = j + 1  # 根据题目要求,起始位置从1开始计数

    # 输出最大子段和,起始位置和结束位置
    print(max_sum, start + 1, end + 1)  # 加1是因为题目要求的位置是从1开始计数



n = int(input())
while n != -1:
    a = list(map(int, input().split()))
    solve(a, n)
    n = int(input())

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值