最长公共前缀 python_【LeetCode】14.最长公共前缀(python版)

题目描述:

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

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

示例 1:

输入: ["flower","flow","flight"]

输出: "fl"

示例 2:

输入: ["dog","racecar","car"]

输出: ""

解释: 输入不存在公共前缀。

说明:

所有输入只包含小写字母 a-z 。

思路:

本题虽然只是“容易”等级的题目,但是可以有至少五种解法,而且这是一个在搜索领域中很常见的问题,所以还是值得一看。

暴力解法:

先找到两个字符串的公共前缀,再将前缀与第三个字符串比较…,这种方法最坏情况下的时间复杂度为O(S)O(S)O(S),其中 S 代表所有字符串的总长度。

class Solution:

def longestCommonPrefix(self, strs: List[str]) -> str:

if len(strs) == 0:

return ''

s = strs[0]

for t in strs[1:]:

long_common_prefix = ''

for p, q in zip(s, t):

if p == q:

long_common_prefix += p

else:

break

s = long_common_prefix

# 出现空串时提前结束

if s == '':

return ''

return s

暴力算法的实现上可以稍微转变思路,传统的寻找共同子串是一个“加法”操作,每找到一个相同字符就就添加进变量 long_common_prefixlong\_common\_prefixlong_common_prefix 。实际上也可以采用“减法”操作,在 t 串中寻找 s 串,假如没找到或者不是在开头,就缩短 s 串。这样实际上并没有减少时间复杂度,只是写法上更简单。

class Solution:

def longestCommonPrefix(self, strs: List[str]) -> str:

if len(strs) == 0:

return ''

long_common_prefix = strs[0]

for s in strs[1:]:

while s.find(long_common_prefix) != 0:

long_common_prefix = long_common_prefix[:-1]

if long_common_prefix == '':

return ''

return long_common_prefix

纵向扫描:可以想象把所有字符串堆叠起来,依次比较所有字符串的第一个字符、第二个字符、第三个字符…,直到遇到某个位置的字符不全相等。同样需要比较所有字符,所以时间复杂度不变

class Solution:

def longestCommonPrefix(self, strs: List[str]) -> str:

if len(strs) == 0:

return ''

for i in range(len(strs[0])):

for s in strs[1:]:

if i == len(s) or s[i] != strs[0][i]:

return s[:i]

return strs[0]

分治法:对于方法2,可以采用分治思想,将数组从中间一分为二,分别求两边子数组的最长公共前缀。而每一个子数组也可以一分为二…

分治法实际上也没有减少比较的次数,因此时间复杂度不变。同时因为采用了递归,所以空间复杂度为O(m⋅log(n))O(m\cdot log(n))O(m⋅log(n)), n为字符串个数,m为字符串长度

class Solution:

def longestCommonPrefix(self, strs: List[str]) -> str:

if len(strs) == 0:

return ''

return self.split_list(strs, 0, len(strs)-1)

def split_list(self, strs, start, end):

if start == end:

return strs[start]

else:

middle = (end + start) // 2

left_str = self.split_list(strs, start, middle)

right_str = self.split_list(strs, middle + 1, end)

return self.get_common_prefix(left_str, right_str)

def get_common_prefix(self, s, t):

min_len = min(len(s), len(t))

for i in range(min_len):

if s[i] != t[i]:

return s[:i]

return s[:min_len]

二分查找法:

这里借用官方题解的图进行说明。首先找到所有字符串最短的长度,因为这是最终答案的最大可能长度。根据这个最短字符串S进行二分查找,那么查找区间为(0,minLen)(0, minLen)(0,minLen)。每次区间一分为二,丢弃不可能包含正确答案的那一半。具体来说二分查找中会出现两种情况:

① S[0, mid]是其余所有字符串的前缀,那么对于S[0, i] (i < mid)来说,它都是所有串的公共前缀。由于想要找的是最长的公共前缀,所以可以把前半个区间丢弃

② S[0, mid]不是其余所有字符串的前缀,那么对于S[0, i] (i > mid)来说,它更不可能是所有串的公共前缀,所以可以丢弃后半个区间

class Solution:

def longestCommonPrefix(self, strs: List[str]) -> str:

if len(strs) == 0:

return ''

def is_common_prefix(prefix, str_list):

for s in str_list:

if s[:len(prefix)] != prefix:

return False

return True

min_str = min(strs, key=len)

start, end = 0, len(min_str)

while start < end:

mid = (end + start + 1) // 2

if is_common_prefix(min_str[:mid], strs):

start = mid

else:

end = mid - 1

return min_str[:(end + start) // 2]

一些使用 Python 的奇淫技巧(来自于官方讨论区中 @xshura 用户的回答):

① Python 中字符串是可以进行比较的,原生的 min()和 max()函数甚至 sort()函数会根据单个字符的 ascii码排序,例abb, aba,abac,最大为abb,最小为aba。所以只需要比较最大最小的公共前缀就是整个数组的公共前缀

def longestCommonPrefix(self, strs):

if not strs: return ""

s1 = min(strs)

s2 = max(strs)

for i,x in enumerate(s1):

if x != s2[i]:

return s2[:i]

return s1

②. 方法三如果使用python,可以有更加简单的写法

class Solution:

def longestCommonPrefix(self, strs: List[str]) -> str:

s = ""

"""

>>> a = [[1,2,3], [4,5,6]]

>>> zip(*a)

>>> [[1,4], [2,5], [3,6]]

"""

for i in zip(*strs):

if len(set(i)) == 1:

s += i[0]

else:

break

return s

一颗随风而倒的墙头草

发布了58 篇原创文章 · 获赞 12 · 访问量 2万+

私信

关注

标签:return,14,python,len,strs,prefix,common,str,LeetCode

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值