返回

最长公共前缀:在代码执行前,先学会逻辑梳理和思维导图

见解分享

示例

给你一个字符串数组strs,请你找出其中最长的公共前缀。

示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"

示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。

思考

首先,我们需要明确什么是最长公共前缀。最长公共前缀是指一个字符串数组中所有字符串都具有的最长相同前缀。在示例1中,"flower"、"flow"和"flight"的最长公共前缀是"fl",因为这是它们都具有的最长相同前缀。在示例2中,"dog"、"racecar"和"car"没有公共前缀,因此输出为空字符串""。

实现

我们可以使用循环和比较来实现最长公共前缀的算法。首先,我们循环比较字符串数组中的第一个字符串和第二个字符串,找到它们的最长公共前缀。然后,我们再循环比较字符串数组的第二个字符串和第三个字符串,找到它们的最长公共前缀。以此类推,直到我们比较完字符串数组中的所有字符串。最后,我们输出最长公共前缀即可。

def longestCommonPrefix(strs):
    """
    :type strs: List[str]
    :rtype: str
    """
    if not strs:
        return ""
    shortest_str = min(strs, key=len)
    
    for i, char in enumerate(shortest_str):
        for other_str in strs:
            if other_str[i] != char:
                return shortest_str[:i]
    
    return shortest_str

再思考

上面的算法虽然能解决问题,但它存在一个性能问题。我们每次比较两个字符串时,都需要循环比较所有其他字符串。如果字符串数组很大,那么这个算法的运行时间可能会很长。

我们可以通过使用分治法来优化算法。首先,我们将字符串数组分成两半。然后,我们分别计算这两半字符串数组的最长公共前缀。最后,我们比较这两半字符串数组的最长公共前缀,得到整个字符串数组的最长公共前缀。

def longestCommonPrefix(strs):
    """
    :type strs: List[str]
    :rtype: str
    """
    def divide_and_conquer(strs, left, right):
        if left == right:
            return strs[left]
        
        mid = left + (right - left) // 2
        lcp_left = divide_and_conquer(strs, left, mid)
        lcp_right = divide_and_conquer(strs, mid + 1, right)
        
        return lcp_common_prefix(lcp_left, lcp_right)
    
    def lcp_common_prefix(lcp1, lcp2):
        min_len = min(len(lcp1), len(lcp2))
        for i in range(min_len):
            if lcp1[i] != lcp2[i]:
                return lcp1[:i]
        
        return lcp1[:min_len]
    
    if not strs:
        return ""
    
    return divide_and_conquer(strs, 0, len(strs) - 1)

再实现

使用分治法之后,算法的运行时间得到了很大的优化。对于一个长度为n的字符串数组,算法的运行时间从O(n^2)降低到了O(nlogn)。

总结

本文介绍了两种解决LeetCode每日一题:最长公共前缀(No.14)的方法。第一种方法使用循环和比较来实现,第二种方法使用分治法来实现。分治法比循环和比较法更加高效,对于一个长度为n的字符串数组,分治法的运行时间从O(n^2)降低到了O(nlogn)。