最长公共前缀

75 阅读3分钟

最长公共前缀的核心思路是纵向扫描(逐字符对比):

  1. 以第一个字符串为基准,依次取其第 i 个字符;
  2. 遍历数组中其他所有字符串,检查它们的第 i 个字符是否与基准字符一致;
  3. 若某一字符串无第 i 个字符(长度不足),或字符不一致,则返回前 i 个字符组成的前缀;
  4. 若所有字符串的第 i 个字符都一致,继续检查下一个字符;
  5. 若基准字符串的所有字符都匹配完成,返回基准字符串。

代码实现(Python)

python

运行

def longestCommonPrefix(strs: list[str]) -> str:
    # 边界条件:数组为空则返回空字符串
    if not strs:
        return ""
    
    # 以第一个字符串为基准
    base = strs[0]
    # 遍历基准字符串的每个字符(按索引)
    for i in range(len(base)):
        current_char = base[i]
        # 检查其他所有字符串的第i个字符
        for s in strs[1:]:
            # 情况1:当前字符串长度不足i(无第i个字符);情况2:字符不匹配
            if i >= len(s) or s[i] != current_char:
                # 返回前i个字符的前缀
                return base[:i]
    # 所有字符都匹配,返回基准字符串
    return base

代码解释

  1. 边界处理:先判断数组是否为空,避免后续索引越界;

  2. 基准选择:选第一个字符串作为对比基准,简化逻辑;

  3. 逐字符校验

    • 外层循环遍历基准字符串的每个字符索引 i

    • 内层循环遍历数组中其他字符串,检查两个核心条件:

      • i >= len(s):当前字符串长度不足,无法匹配第 i 个字符;
      • s[i] != current_char:字符不匹配;
    • 满足任一条件则立即返回前 i 个字符的前缀;

  4. 完全匹配:若基准字符串的所有字符都通过校验,说明它就是最长公共前缀,直接返回。

测试用例验证

python

运行

# 示例1
print(longestCommonPrefix(["flower","flow","flight"]))  # "fl"
# 示例2
print(longestCommonPrefix(["dog","racecar","car"]))     # ""
# 额外测试:单元素数组
print(longestCommonPrefix(["apple"]))                   # "apple"
# 额外测试:部分匹配
print(longestCommonPrefix(["abc","ab","a"]))            # "a"

复杂度分析

  • 时间复杂度:O (m*n),其中 m 是最长公共前缀的长度,n 是字符串数组的长度。最坏情况下(所有字符串完全相同),需要遍历所有字符串的所有字符;
  • 空间复杂度:O (1),仅使用了固定数量的变量,无额外空间消耗。

补充思路(横向扫描)

另一种常见思路是横向对比:先取前两个字符串的公共前缀,再将该前缀与第三个字符串对比,更新公共前缀,依次类推。代码实现如下(供参考):

python

运行

def longestCommonPrefix(strs: list[str]) -> str:
    if not strs:
        return ""
    prefix = strs[0]
    for s in strs[1:]:
        # 不断缩短前缀,直到找到与当前字符串的公共前缀
        while not s.startswith(prefix):
            prefix = prefix[:-1]
            if not prefix:
                return ""
    return prefix

两种思路各有优劣:纵向扫描在前缀较短时效率更高(提前终止),横向扫描逻辑更直观。推荐优先使用纵向扫描,更符合 “最长公共前缀” 的逐字符匹配逻辑。