题目

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""。

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

纵向扫描

最间接的思路:
选取第一个字符串假如为前缀。
用这个前缀的每一个字符,去和所有其余字符串比拟,如果其余字符串在该地位也是这个字符,那这个字符就属于前缀;反之,前缀就到此结束。

不须要思考选取数组中的第一个字符串是否长度是最小或最长的。因为最差状况就是这个字符串是长度最短的,并且所有字符刚好都是前缀。

工夫复杂度:最坏状况,数组有n个字符串,字符串全都一样且长度为m,O(mn)
空间复杂度:O(1)

def longestCommonPrefix(strs):    firstStr = strs[0]    for i in range(len(firstStr)):        for str in strs[1:]:            if str[i] != firstStr[i]:                return firstStr[0:i] if i > 0 else ''

横向扫描

假如数组中第一个字符串是前缀。
拿假如前缀,和第二个字符串比拟,共有局部是新的前缀。
再拿新的前缀,和第三个字符串比拟,共有局部是新的前缀。
始终如此,比到数组最初一个字符串。

工夫复杂度:最坏状况和之前一样,O(mn)
空间复杂度:O(1)

def longestCommonPrefix(strs):    prefix = strs[0]    for str in strs[1:]:        # 选较短长度作为遍历范畴        for i in range(min(len(prefix), len(str))):            if prefix[i] != str[i]:                prefix = prefix[:i]                break    return prefix

分治法

分治法是一种思维,就是分而治之。

递归是一种编程技巧,分治思维在代码中适宜用递归来实现。

在本题中,将原数组分成两半,别离找出这两局部的公共前缀,再找出这两个前缀的公共前缀,最终就是这个数组的公共前缀。这就是分治思维

工夫复杂度O(mn)
空间复杂度O(mlogn),m是字符串均匀长度,n是字符串数量

def longestCommonPrefix(strs):    def split(start, end):        # 分到不可再分,返回字符串        if start == end:            return strs[start]        mid = (start + end) // 2        # 递归宰割数组        left, right = split(start, mid), split(mid + 1, end)        # 以两个字符串中较小的长度作为遍历范畴        minLen = min(len(left), len(right))        print(left, right, minLen)        for i in range(minLen):            # 当呈现不统一,则该层公共前缀已找到            if left[i] != right[i]:                return left[:i]        # 没有不统一,长度较小的字符串全副遍历完,则长度较小的字符串就是公共前缀        return left[:minLen]    return split(0, len(strs) - 1)

二分法

公共前缀的长度肯定不会超过最小长度的字符串。
咱们再最小长度字符串上应用二分法,将其分成两半,用左半边字符去和每个字符串比拟
如果每个字符串都有,那么就挪动左指针
如果有字符串没有,那么就挪动右指针,放大公共范畴

工夫复杂度:O(mnlogm),其中m是字符串数组中的字符串的最小长度,n是字符串的数量。二分查找的迭代执行次数是O(logm),每次迭代最多须要比拟mn个字符,因而总工夫复杂度是O(mnlogm)。

空间复杂度:O(1)O(1)。应用的额定空间复杂度为常数。

def longestCommonPrefix(strs):    minLen = min(len(str) for str in strs)    left, right = 0, minLen - 1    # 循环条件是<=,left和right会挪动到同一个字符上,有==的状况    while left <= right:        mid = (left + right) // 2        # all()函数,全副为True返回True        allTrue = all(strs[0][:mid + 1] == str[:mid + 1] for str in strs)        if allTrue:            left = mid + 1        else:            right = mid - 1    return strs[0][:left]