编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”
输入:[“flower”,“flow”,“flight”]
输出:“fl”
算法描述:
首先,将列表中的字符串按照长度重新排序,然后依次遍历字符串 [ S 1 … S n ] \left[S_{1} \ldots S_{n}\right] [S1…Sn],首先求 L C P ( S 1 , S 2 ) L C P\left(S_{1}, S_{2}\right) LCP(S1,S2),然后求 L C P ( L C P ( S 1 , S 2 ) , S 3 ) L C P\left(L C P\left(S_{1}, S_{2}\right), S_{3}\right) LCP(LCP(S1,S2),S3),依次类推:
L C P ( S 1 … S n ) = L C P ( L C P ( L C P ( S 1 , S 2 ) , S 3 ) , … S n ) L C P\left(S_{1} \ldots S_{n}\right)=L C P\left(L C P\left(L C P\left(S_{1}, S_{2}\right), S_{3}\right), \ldots S_{n}\right) LCP(S1…Sn)=LCP(LCP(LCP(S1,S2),S3),…Sn)
Python3实现
def longestCommonPrefix(strs):
if len(strs) == 0:
return ""
else:
strs = sorted(strs, key=len)
prefix = strs[0]
for i in range(1,len(strs)):
while strs[i].find(prefix) != 0:
prefix = prefix[0:len(prefix)-1]
if len(prefix) == 0:
return ""
return prefix
算法描述
这个算法的思路来自于LCP操作的结合律。 我们可以发现:
L C P ( S 1 … S n ) = L C P ( L C P ( S 1 … S k ) , L C P ( S k + 1 … S n ) ) L C P\left(S_{1} \ldots S_{n}\right)=L C P\left(L C P\left(S_{1} \ldots S_{k}\right), L C P\left(S_{k+1} \ldots S_{n}\right)\right) LCP(S1…Sn)=LCP(LCP(S1…Sk),LCP(Sk+1…Sn))
,其中 LCP ( S 1 … S n ) \operatorname{LCP}\left(S_{1} \ldots S_{n}\right) LCP(S1…Sn)是字符串 [ S 1 … S n ] \left[S_{1} \ldots S_{n}\right] [S1…Sn]的最长公共前缀, 1 < k < n 1
为了应用上述的结论,我们使用分治的技巧,将原问题 L C P ( S i ⋯ S j ) L C P\left(S_{i} \cdots S_{j}\right) LCP(Si⋯Sj)分成两个子问题 L C P ( S i ⋯ S m i d ) L C P\left(S_{i} \cdots S_{m i d}\right) LCP(Si⋯Smid)与 L C P ( S m i d + 1 , S j ) L C P\left(S_{m i d+1}, S_{j}\right) LCP(Smid+1,Sj)。
其中mid = i + j 2 \frac{i+j}{2} 2i+j。 我们用子问题的解 lcpLeft 与 lcpRight 构造原问题的解。 从头到尾挨个比较 lcpLeft 与 lcpRight 中的字符,直到不能再匹配为止。 计算所得的 lcpLeft 与 lcpRight 最长公共前缀就是原问题的解。
Python3实现
def longestCommonPrefix(strs):
def recursion(strs, l, r):
if l == r:
return strs[l]
else:
mid = (l+r)//2
lcpLeft = recursion(strs, l, mid)
lcpRight = recursion(strs, mid+1, r)
return commonPrefix(lcpLeft,lcpRight)
def commonPrefix(left, right):
while right.find(left) != 0:
left = left[0:len(left)-1]
if len(left) == 0:
return ""
return left
if len(strs) == 0:
return ""
else:
return recursion(strs, 0, len(strs)-1)
算法描述
应用二分查找法找到所有字符串的公共前缀的最大长度 L。 算法的查找区间是 ( 0 … min L e n ) (0 \ldots \min L e n) (0…minLen),其中 minLen 是输入数据中最短的字符串的长度,同时也是答案的最长可能长度。 每一次将查找区间一分为二,算法进行的过程中一共会出现两种可能情况:
S[1…mid] 不是所有串的公共前缀。 这表明该前缀加上mid后面的字符也一定不是公共前缀,于是我们就可以丢弃后半个查找区间。
S[1…mid] 是所有串的公共前缀。 这表示该前缀加上mid后面的字符有可能也是公共前缀,因为我们要找最长的公共前缀,所以我们将mid后的字符附加在S[1…mid]后继续进行匹配。
Python3实现
def longestCommonPrefix(strs):
def isCommonPrefix(strs, length):
for i in range(1,len(strs)):
if strs[i].find(strs[0][0:length+1]) == 0:
continue
else:
return False
return True
if len(strs) == 0:
return ""
else:
strs = sorted(strs, key=len)
low, high = 0, len(strs[0])-1
while low <= high:
mid = (low + high) // 2
if isCommonPrefix(strs, mid):
low = mid + 1
else:
high = mid - 1
print ((low + high) // 2)
return strs[0][0:(low + high) // 2 + 1]