首页 > 试题广场 >

查找两个字符串a,b中的最长公共子串

[编程题]查找两个字符串a,b中的最长公共子串
  • 热度指数:197521 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
\hspace{15pt}对于给定的两个字符串 st,你需要找出它们的最长公共子串。特别地,如果存在多个答案,输出在较短串中最先出现的那个。

\hspace{15pt}子串为从原字符串中,连续的选择一段字符(可以全选、可以不选)得到的新字符串。
\hspace{15pt}如果字符串 a 的一个子串 a' 与字符串 b 的一个子串 b' 完全相等,那么子串 a',b' 是字符串 a,b 的一个公共子串

输入描述:
\hspace{15pt}第一行输入一个长度为 1 \leqq {\rm len}(s) \leqq 300、仅由小写字母组成的字符串 s
\hspace{15pt}第二行输入一个长度为 1 \leqq {\rm len}(t) \leqq 300、仅由小写字母组成的字符串 t


输出描述:
\hspace{15pt}输出一个字符串,代表 st 的最长公共子串。如果存在多个答案,输出在较短串中最先出现的那个。
示例1

输入

awaabb
aawbb

输出

aa

说明

\hspace{15pt}在这个样例中,\texttt{\texttt{ 都是 st 的最长公共子串,但 \texttt{ 在较短串 s 中首先出现,因此输出 \texttt{
示例2

输入

abcdefghijklmnop
abcsafjklmnopqrstuvw

输出

jklmnop
import sys

#滑动窗口
s = str(input())
t = str(input())
temp = ''
#用短的字符串和其子串去长的字符串里面滑动比较
if len(s) <= len(t):
    for i in range(len(s)):
        for j in range(len(s),i,-1):
            if s[i:j] in t and len(s[i:j])>len(temp):
                temp = s[i:j]
else:
    for i in range(len(t)):
        for j in range(len(t),i,-1):
            if t[i:j] in s and len(t[i:j])>len(temp):
                temp = t[i:j]
print(temp[::])
发表于 2025-02-19 19:50:08 回复(0)
经典DP,不过记得先把长短统一
s1 = input()
s2 = input()

l1, l2 = len(s1), len(s2)
if l1 > l2:
    s1, s2 = s2, s1
    l1, l2 = l2, l1

# dp[i][j] ---> 最大公共子串得长度,该子串分别以s1[i-1]和s2[j-1]结尾
dp = [[0 for _ in range(1 + l2)] for _ in range(1 + l1)]

max_len = -1
max_len_index_s1 = -1
for i in range(1, 1 + l1):
    for j in range(1, 1 + l2):
        if s1[i - 1] == s2[j - 1]:
            dp[i][j] = 1 + dp[i - 1][j - 1]
            if dp[i][j] > max_len:
                max_len = dp[i][j]
                max_len_index_s1 = i - 1

assert max_len >= 0
assert max_len_index_s1 >= 0

# print(max_len)
# print(max_len_index_s1)

print(s1[max_len_index_s1 + 1 - max_len : max_len_index_s1 + 1])


发表于 2024-09-24 20:31:32 回复(0)
a=input()
b=input()
test=[]
res=[]
lenth=[]
if len(a)>len(b):
    chang=a
    duan=b
else:
    chang=b
    duan=a
if duan in chang:
    print(duan)
else:
    test=list(duan).copy()
    for i in range(len(duan)):
        test=list(duan).copy()[i:]
        if ''.join(test) in chang:
            res.append(''.join(test))
            lenth.append(len(''.join(test)))
        else:
            for j in range(1,len(test)):
                if ''.join(test[:-(j)]) in chang:
                    res.append(''.join(test[:-(j)]))
                    lenth.append(len(''.join(test[:-(j)])))
                    break
print(res[lenth.index(max(lenth))])
发表于 2024-09-14 00:57:17 回复(0)
while True:
    try:
        s1 = input()
        s2 = input()
        n = 0
        max_sub = ''
        if len(s2)<len(s1):
            s1, s2 = s2, s1
        for i in range(len(s1)):
            if s1[i-n:i+1] in s2:
                max_sub = s1[i-n:i+1]
                n += 1
        print(max_sub)
    except:
        break

发表于 2024-08-13 14:53:54 回复(1)
# 也是服了,存在多解时例子的答案只有一个就算了,
# 关键还不是第一个找到的(在str1位置靠前的)
# 以下动态规划代码,dp数组直接存储子串
"""
最长公共子串问题动态规划时关键在于状态的定义,比较巧妙
dp[i][j]表示以str1的第i个字符和str2的第j个字符结尾的公共子串。
注意,是以str1第i个字符和str2第j个字符结尾的公共子串,
如果str1第i个字符和str第j个字符不相等,那么不可能存在以它们结尾的公共子串。认为空字符''
那么状态转移方程容易得出:如果str1第i个字符和str第j个字符相等,
那么dp[i][j]就是dp[i-1][j-1]+str1[i-1],因为多了一个公共字符,
如果str1第i个字符和str第j个字符不相等,那么以它们结尾的公共子串不存在,dp[i][j]=''
"""

def longest_common_substring(str1, str2):
    m = len(str1)
    n = len(str2)
    dp = [[""] * (n + 1) for _ in range(m + 1)]  # 状态直接存储子串
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + str2[j - 1]
    flattened_dp = [item for sublist in dp for item in sublist]
    # flattened_dp.reverse()
    return max(flattened_dp, key=lambda x: len(x))


import sys

lines = []
for line in sys.stdin:
    line = line.strip()
    if line == "":
        break
    lines.append(line)

str1, str2 = lines
print(longest_common_substring(str1, str2))

发表于 2024-05-01 00:22:48 回复(0)
s1,s2=input(),input()
#强制s1长度<s2长度
if len(s1)>len(s2):
    s1,s2=s2,s1
sum_len,str=len(s1),''
for i in range(1,sum_len+1):
    for j in range(0,sum_len):
        if s1[j:i] in s2 and len(s1[j:i]) > len(str):#若有多个,输出在较短串中最先出现的那个
            str=s1[j:i]
print(str)

编辑于 2024-04-25 00:08:00 回复(0)
a=input()
b=input()
if len(a)>len(b):
    a,b=b,a
str=''
for i in range(len(a)-1):
    for j in range(len(a),i+1,-1):
        if a[i:j] in b and len(a[i:j])>len(str):
            str=a[i:j]
print(str)

编辑于 2024-03-26 10:43:19 回复(0)
word1 = input()
word2 = input()
if len(word1) >= len(word2):
    word1, word2 = word2, word1
list1 = []
list2 = []
for i in range(len(word1)):
    for j in range(i + 1, len(word1) + 1):
        list1.append(word1[i:j])
for k in range(len(word2)):
    for v in range(k + 1, len(word2) + 1):
        list2.append(word2[k:v])

list3 = list(set(list1) & set(list2))
sort_list = sorted(list3, key=lambda x: len(x), reverse=True)

max_len = len(sort_list[0])
short_list = None
for l in sort_list:
    if len(l) == max_len:
        if short_list is None or list1.index(l) < list1.index(short_list):
            short_list = l
print(short_list)

发表于 2024-03-22 14:41:49 回复(0)
a,b=input().strip(),input().strip()
#让a时长度较短的哪一个
if len(a)>len(b):
    a,b=b,a
c=[]
for i in range(len(a)):
    for j in range(i+1,len(a)+1):
        if a[i:j] in b:
            c.append(a[i:j])
#找到最长公共子串,同时时最先出现的那个
substr=''
for k in c:
    if len(k)>len(substr):
        substr=k
print(substr)
发表于 2023-09-13 10:03:29 回复(0)
s1 = input()
s2 = input()
# 让s1为最短
if len(s1) > len(s2):
    s1,s2 = s2,s1
n = len(s1)

res = ''
# 滑窗
r=l=0
while r<n:
    
    if s1[l:r+1] in s2 and r-l+1 > len(res):
        res = s1[l:r+1]
        
    r+=1
    
    while l<r and s1[l:r+1] not in s2:
        l+=1

print(res)

发表于 2023-07-27 14:46:28 回复(0)
滑窗卷积
# 暴力滑窗
str_i = input()
str_j = input()
if(len(str_i) > len(str_j)): str_i,str_j = str_j,str_i
for i in range(len(str_i)-1): str_j = "\r"+str_j+"\r"

max_len = 0
max_len_pos = -1
for j in range(len(str_j)-len(str_i)+1):
    temp_len = 0
    for i in range(len(str_i)):
        if(str_i[i] == str_j[j+i]):
            temp_len += 1
            if(temp_len > max_len):
                max_len = temp_len
                max_len_pos = i+1-temp_len
            elif(temp_len == max_len):
                head_pos = i+1-temp_len
                if(head_pos < max_len_pos): max_len_pos = head_pos
        else:
            temp_len = 0
#print(max_len_pos)
for i in range(max_len): print(str_i[max_len_pos+i],end = "")


发表于 2023-07-26 19:43:56 回复(0)
我想问下,这个要返回 子串, 如果有多个相同的子串 如何返回呢?  比较困惑,是返回第一次出现的位置,还是最后一次出现的位置呢? 

efgyiffxoonftmmvd
exwzdcwjsttuhsxrcpzplpnfqxqsqtlfctdkgacejitayoafucmfxxhkxyixxykndchyjc

比如这个例子: 返回 yi or nf ? 这个我比较困惑, 
预期输出yi ,但我返回的 nf  但这个也有错吗? 题目并没有说明白.

代码 放在下面了,有大佬帮忙解释一下吗
# -*- coding: utf-8 -*-
"""
@Time    : 2023/5/19 08:25
@Author  : Frank
@File    : HJ56.py

HJ65 查找两个字符串a,b中的最长公共子串


描述
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!

数据范围:字符串长度


输入描述:
输入两个字符串



dp 问题

dp


if str1[i - 1] == str2[j - 1]
    dp[i][j] = dp[i - 1][j - 1] + 1
else:
    dp[i][j] = 0



返回公共的字符串 可能有多个。

如下面的例子:
公共子串的长度是3,但是有两个不同的子串
gcn
nlo



nvlrzqcjltmrejybjeshffenvkeqtbsnlocoyaokdpuxutrsmcmoearsgttgyyucgzgcnurfbubgvbwpyslaeykqhaaveqxijc

wkigrnngxehuiwxrextitnmjykimyhcbxildpnmrfgcnevjyvwzwuzrwvlomnlogbptornsybimbtnyhlmfecscmojrxekqmj
"""


def prepare_data():
    str1 = input()
    str2 = input()
    return str1, str2
    pass


def lc_substr(str1, str2):
    n = len(str1)
    m = len(str2)

    dp = [[0 for j in range(m + 1)] for i in range(n + 1)]

    max_len = 0
    index = 0

    # 下标从1开始
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            # 注意这里 比较 i-1 and j-1 这个表示当前的字符
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
                if dp[i][j] >= max_len:
                    max_len = dp[i][j]
                    index = i
            else:
                dp[i][j] = 0

    return str1[index - max_len:index]


if __name__ == '__main__':
    # s = 'abcde'
    # s2 = 'cde'

    s, s2 = prepare_data()
    # s = 'nvlrzqcjltmrejybjeshffenvkeqtbsnlocoyaokdpuxutrsmcmoearsgttgyyucgzgcnurfbubgvbwpyslaeykqhaaveqxijc'
    # s2 = 'wkigrnngxehuiwxrextitnmjykimyhcbxildpnmrfgcnevjyvwzwuzrwvlomnlogbptornsybimbtnyhlmfecscmojrxekqmj'
    print(lc_substr(s, s2))




发表于 2023-05-19 10:13:10 回复(2)
a = input().strip()
b = input().strip()
if len(a) > len(b):
    temp = a
    a = b
    b = temp

max_sub = ''
for i in range(len(a)):
    for j in range(len(a), i, -1):
        if (a[i:j] in b) and (len(max_sub) < len(a[i:j])):
            max_sub = a[i:j]

print(max_sub)

发表于 2023-05-18 15:24:22 回复(1)
us1,us2 = input(),input()
ll = []
if len(us1) > len(us2):
    us1,us2 = us2,us1
for _idx in range(len(us1) + 1):
    for j in range(_idx):
        _s = us1[j:_idx]
        if _s in us2:
            ll.append(_s)
print(sorted(ll, key=len, reverse=True)[0])
发表于 2023-04-20 23:16:12 回复(0)
def max_same_str(a,b):
    c=[]
    d=[]
    for i in range(len(a)):
        for j in range(i+1,len(a)+1):
            if a[i:j] in b:
                c.append(a[i:j])
                d.append(len(a[i:j]))
    x=max(d)
    y=c[d.index(x)]
    print(y)

while True:
    try:
        s1=input()
        s2=input()
        if len(s2)>len(s1):
            max_same_str(s1,s2)
        else:
            max_same_str(s2,s1)
    except:
        break


发表于 2023-03-19 21:39:44 回复(0)
str1,str2 = input() ,input() 
total_list = []
if len(str1)>len(str2):
    str1,str2 = str2,str1
for i in range(len(str1)):
    for j in range(len(str1)):
        if j+i+1<len(str1):
            if str1[i:j+i+1] in str2:
                total_list.append(str1[i:j+i+1])
print(max(total_list,key=len))

使用迭代思想对a进行切片,将包含在b中的所有切片放入一个列表,最后取出列表中长度最长的元素

发表于 2023-03-16 21:53:45 回复(0)
#动态规划解题
def solution(a,b):
    dp = [[0 for i in range(len(a)+1)] for j in range(len(b)+1)]
    l_max = 0
    for i in range(1,len(b)+1):
        for j in range(1,len(a)+1):
            if b[i-1] == a[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            if dp[i][j] > l_max :
                l_max = dp[i][j]
    #用于找出第一个出现的最长字串,必须在短串中找,所以得确定a,b的长短
    for i in range(1,len(a)+1):
        for j in range(1,len(b)+1):
            if dp[j][i] == l_max:
                print(a[i-l_max:i])#注意dp中的i、j对应上字符时始终大1
                return

a,b= input(),input()
#用于保证传入的参数,始终为短串在前、长串在后
temp = a
a = a if len(b)>len(a) else b
b = temp if len(temp)>len(b) else b
solution(a,b)

发表于 2023-02-28 17:21:59 回复(0)
第二个for这里忘记 -i了卡半天
while True:
    try:
        arr1 = input()
        arr2 = input()
        short, long = '', ''
        if len(arr1) < len(arr2):
            short = arr1
            long = arr2
        else:
            long = arr1
            short = arr2
        if short in long:
            print(short)
        else:
            for i in range(len(short)-1, 0, -1):
                for j in range(0, len(short)-i):
                    arr = short[j:j + i + 1]
                    if arr != '' and arr in long:
                        print(arr)
                        break
                    else:
                        continue
                else:
                    continue
                break
    except:
        break

发表于 2023-02-23 16:39:02 回复(0)
a,b = input(),input()
if len(a)<len(b):
    a,b = b,a

f = True
for i in range(len(b)-1,0,-1):
    if not f:
        break
    for j in range(0,len(b)-i+1):
        if b[j:j+i] in a:
            print(b[j:j+i])
            f =  False
            break

发表于 2023-02-22 14:49:16 回复(0)
s1, s2 = input(), input()
s0 = ""
list1, list2 = [], []
if len(s1) > len(s2):
    s0 = s1
    s1 = s2
    s2 = s0
for i in range(len(s1)):
    for j in range(i + 1, len(s1) + 1):
        if s1[i:j] in s2:
            list1.append(s1[i:j])
list1 = sorted(list1, key=lambda x: len(x))
for i in list1:
    if len(i) == len(list1[-1]):
        list2.append(i)
for i in list2:
    if i in s1:
        print(i)
        break
发表于 2023-02-14 11:39:13 回复(0)