LeetCode专题-Python实现之第14题:Longest Common Prefix 1、读题 2、解题 3、第一次优化

导航页-LeetCode专题-Python实现

相关代码已经上传到github:https://github.com/exploitht/leetcode-python
文中代码为了不动官网提供的初始几行代码内容,有一些不规范的地方,比如函数名大小写问题等等;更合理的代码实现参考我的github repo

Write a function to find the longest common prefix string amongst an array of strings.

很简单的一句话,寻找一个字符串数组的最大公共前缀字符子串
举个简单的例子,如下字符串列表:
['abc', 'abcd', 'abd']
的最大公共前缀是'ab'

2、解题

最简单粗暴的方式,遍历嘛,搞一个前缀,前缀从短变长,去匹配整个字符串数组,就能找到公共前缀。基于这种思路,有了如下代码:

class Solution(object):
    def longestCommonPrefix(self, strs):
        """
        :type strs: List[str]
        :rtype: str
        """
        # 空列表判断
        if not strs:
            return ''
        # 取第一个字符串来寻找前缀
        first_str = strs[0]
        prefix = ''
        for i in range(len(first_str)):
            prefix = first_str[:i + 1]
            # 如果strs中每一个字符串都是以prefix开头,那么prefix就是前缀
            if all(map(lambda x: x.startswith(prefix), strs)):
                continue
            else:
                break
        else:
            return prefix
        return prefix[:-1]

3、第一次优化

上面这种实现方式用一次循环来取出一个前缀,然后循环遍历字符串数组判断前缀是否正确,也就是O(n2)的时间复杂度(n的平方)

能不能优化一点呢,思考有序比无序简单,是否可以先排序?Python的sorted函数排序性能可是杠杠的,Timsort算法在最坏情况也有n log n的表现,快排一般也是这个复杂度,但是最坏情况是n平方。

如果有序,怎样寻找前缀呢?观察一个有序的例子:['abcd','abce','abd','ad'],第一个和第二个比较,能够得到的子串一般相对较长,但是越往后呢,对了,不会变长,只会变短或者不变。也就是首尾对比就能够得到结果。于是乎有了下面解题方式:

class Solution(object):
    def longestCommonPrefix(self, strs):
        """
        :type strs: List[str]
        :rtype: str
        """
        # 如果字符串数组为空,或者有一个元素但是是空字符串,则返回空字符串
        # 先排序
        strs_list = sorted(strs)
        if not strs or not strs[0]:
            return ''
        # # 先排序
        # strs_list = sorted(strs)
        # 前缀初始化为空字符串,然后循环递增
        prefix = ''
        for i in range(len(strs_list[0])):
            prefix = strs_list[0][:i + 1]
            # 判断排序后的字符串数组首尾是否有公共前缀,all判断比and快
            # if all([strs_list[0].startswith(prefix), strs_list[-1].startswith(prefix)]):
            if strs_list[0].startswith(prefix) and strs_list[-1].startswith(prefix):
                continue
            else:
                # 不满足if,也就是prefix多加了一位的情况,对应最后一行的 return prefix[:-1]
                break
        else:
            # 不是break结束循环,则执行这里
            return prefix
        return prefix[:-1]

如上实现,排序的时间复杂度是O(n)或者O(n log n),寻找子串的时间复杂度是O(n)级别,合在一起也就是O(n)或者O(n + n log n)