You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取两个Strings中首次出现的公共substrings?

如何获取两个字符串中首次出现的公共子串

嘿,这个需求我之前也帮人捋过,刚好给你梳理几种实用的实现思路和代码,分不同场景给你参考~先跟你对齐下需求:咱们要找的是两个字符串里都存在、且在各自字符串中出现位置最早的公共子串对吧?一般大家默认要的是最长的那个首次出现的,我先按这个来,也会提下如果要找任意长度的情况怎么调整~

方法一:暴力匹配法(简单易上手,适合短字符串)

这个方法属于入门级,思路特别直白——遍历第一个字符串的所有可能子串,按出现顺序检查是否在第二个字符串里,为了找最长的,咱们从最长的子串开始往下查,找到第一个符合条件的直接返回就行。

Python代码实现:

def first_common_substring(str1, str2):
    # 先把短的字符串放前面,减少遍历次数
    if len(str1) > len(str2):
        str1, str2 = str2, str1
    
    # 从最长的可能子串长度开始往下遍历
    for length in range(len(str1), 0, -1):
        # 逐个取出当前长度的子串
        for i in range(len(str1) - length + 1):
            substr = str1[i:i+length]
            # 检查这个子串是否在第二个字符串里
            if substr in str2:
                # 因为从最长开始找,第一个找到的就是最长的首次出现的公共子串
                return substr
    # 没有公共子串的话返回空串
    return ""

用法示例:

s1 = "hello world"
s2 = "worxxhello"
print(first_common_substring(s1, s2))  # 输出 "hello"

⚠️ 缺点:如果字符串很长,效率会很低,时间复杂度是O(n²*m)(n是短串长度,m是长串长度),适合小字符串场景。

方法二:滑动窗口法(效率更高,适合中等长度字符串)

要是你的字符串长度中等,暴力法就有点慢了,这时候滑动窗口法更合适。思路是把其中一个字符串固定,另一个“滑”过去,每次检查重叠部分的公共子串,记录最早出现的最长匹配。

Python代码实现:

def first_common_substring_sliding(str1, str2):
    max_match_len = 0
    match_start_idx = 0

    # 遍历所有可能的重叠起始位置
    for i in range(len(str1)):
        for j in range(len(str2)):
            k = 0
            # 计算当前重叠部分的最长连续匹配长度
            while i + k < len(str1) and j + k < len(str2) and str1[i+k] == str2[j+k]:
                k += 1
            # 如果当前找到的匹配更长,就更新记录(因为是按顺序遍历,第一个更长的就是最早出现的)
            if k > max_match_len:
                max_match_len = k
                match_start_idx = i
    
    if max_match_len == 0:
        return ""
    # 返回str1中对应的子串(也可以从str2取,结果一样)
    return str1[match_start_idx:match_start_idx+max_match_len]

这个方法的时间复杂度是O(n*m),比暴力法提升不少,大部分日常场景都够用。

方法三:后缀数组法(最优效率,适合超大字符串)

要是你处理的是百万级字符的超大字符串,上面俩方法就扛不住了,这时候得用后缀数组的思路——把两个字符串用一个特殊分隔符(比如#,注意这个字符不能在两个原字符串里出现)拼接起来,生成所有后缀后排序,找相邻后缀中跨分隔符的最长公共前缀,就是咱们要的最长公共子串,再确认下出现位置是不是最早的就行。

Python简化版实现:

def first_common_substring_suffix(str1, str2):
    separator = '#'
    # 拼接两个字符串,用分隔符区分开
    combined_str = str1 + separator + str2
    # 生成所有后缀
    suffixes = [combined_str[i:] for i in range(len(combined_str))]
    # 排序后缀,这样有公共前缀的后缀会挨在一起
    suffixes.sort()

    max_match_len = 0
    result_substr = ""

    # 遍历排序后的后缀,找跨分隔符的最长公共前缀
    for i in range(len(suffixes)-1):
        s_a = suffixes[i]
        s_b = suffixes[i+1]
        # 检查两个后缀是不是分别来自原两个字符串
        has_sep_a = separator in s_a
        has_sep_b = separator in s_b
        if has_sep_a != has_sep_b:
            k = 0
            # 计算公共前缀长度
            while k < len(s_a) and k < len(s_b) and s_a[k] == s_b[k]:
                k += 1
            # 更新最长匹配
            if k > max_match_len:
                max_match_len = k
                result_substr = s_a[:k]
    
    if not result_substr:
        return ""
    # 确认这个子串在原字符串中的首次出现位置,确保是最早的
    idx_in_str1 = str1.index(result_substr)
    idx_in_str2 = str2.index(result_substr)
    # 如果有多个同长度的子串,这里可以根据需求调整,比如选在str1中出现最早的
    return result_substr

这个方法的时间复杂度主要在排序后缀,是O((n+m)log(n+m)),处理超大字符串特别高效。

额外注意点

  • 如果你的需求是任意长度的第一个出现的公共子串(比如只要找到第一个相同的字符就行),那可以把暴力法里的遍历顺序反过来,从长度1开始,找到第一个存在的子串就返回。
  • 大小写敏感问题:如果需要忽略大小写,先把两个字符串都转成小写(或大写)再处理。
  • 空字符串处理:提前判断如果其中一个字符串是空的,直接返回空串就行。

内容的提问来源于stack exchange,提问作者MaeLstroms Stroms

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:57:22