📜  这至少两个字符串的前缀字符串最长的字符串(1)

📅  最后修改于: 2023-12-03 15:28:19.731000             🧑  作者: Mango

最长公共前缀

在程序设计中,常常需要比较多个字符串的公共前缀。本篇文章将介绍如何求解至少两个字符串的前缀字符串最长的字符串。

问题描述

给定一组字符串,找到它们共有的最长的前缀字符串。

例如,

字符串: ["flower", "flow", "flight"]
最长公共前缀: "fl"

又例如,

字符串: ["dog", "racecar", "car"]
最长公共前缀: ""
解法一:暴力枚举

最直接的方法是将所有字符串的前缀进行比较,取最长的共同前缀。

代码如下:

def longestCommonPrefix(strs):
    if not strs:
        return ""
    min_len = min([len(s) for s in strs])
    common_prefix = ""
    for i in range(min_len):
        cur_char = strs[0][i]
        for s in strs[1:]:
            if s[i] != cur_char:
                return common_prefix
        common_prefix += cur_char
    return common_prefix

时间复杂度:$O(n \cdot m)$,其中 $n$ 是字符串序列长度, $m$ 是字符串平均长度。最坏情况下需要比较每一个字符的前缀。

解法二:二分查找

对于解法一,存在大量冗余的字符串比较,因此可考虑优化。

事实上,对于任意一个字符串,其前缀也一定是它任意子串的前缀。

因此,我们可以利用这个性质进行优化。具体步骤为:

  1. 我们先取第一个字符串的第 $len/2$ 个字符截断,比较其是否为其他所有字符串的前缀,如果是,则前缀的长度可能为 $len/2$ 或更长,可以取后 $len/2$ 的字符再继续二分查找;如果否,则前缀的长度可能在 $[0, len/2)$ 内,取前 $len/2$ 的字符继续二分查找。

  2. 重复以上步骤,直到得到最长公共前缀。

代码如下:

def longestCommonPrefix(strs):
    if not strs:
        return ""
    min_len = min([len(s) for s in strs])

    def is_common_prefix(length):
        prefix = strs[0][:length]
        for s in strs[1:]:
            if s[:length] != prefix:
                return False
        return True

    left, right = 0, min_len
    while left < right:
        mid = (left + right + 1) // 2
        if is_common_prefix(mid):
            left = mid
        else:
            right = mid - 1

    return strs[0][:left]

时间复杂度:$O(n\cdot m\cdot logm)$,其中 $n$ 是字符串序列长度, $m$ 是字符串平均长度。

总结

本文介绍了两种求解最长公共前缀的算法。暴力枚举法解题思路简单,但时间复杂度较高,不适用于大规模数据,需要优化。

二分查找法可以大幅减少冗余的字符串比较,算法时间复杂度更低。本方法适用于任意多个字符串的情况。

值得一提的是,很多编程语言库或内置函数都有求解最长公共前缀的函数,如 C++ 的 string 库中的 substr() 函数,Python 的 os.path.commonprefix() 函数等,读者也可根据自己的需要选择使用,不必重新造轮子。