Write a function to find the longest common prefix string amongst an array of strings.
大概的思路是:首先找到input中string的最小长度L,然后把每个string从L/2处一分为二,先比较[0, L/2]是否是common prefix。如果前一半是,则比较[L/2+1, 3/4*L];如果前一半不是,则比较[0,L/4]。
在下面这个implementation中,由于recursion完全在checkPrefix
这个函数中进行,且在每一层会call这个函数两次,因此不是很efficient。
def longestCommonPrefix(self, strs: List[str]) -> str:
try:
n = np.min([len(word) for word in strs])
except ValueError:
return ''
if n==0:
return ''
strs = [word[:n] for word in strs]
re = checkPrefix(strs, l=0, r=n)
return strs[0][:re]
def checkPrefix(self, strs, l, r):
# stop case
if l == r-1:
first = strs[0]
for word in strs:
if word[l]!=first[l]:
return l
return r
else:
mid = l + math.ceil((r-l)/2)
# recursive call 1
if checkPrefix(strs, l, mid)==mid:
# recursive call 2
return checkPrefix(strs, mid, r)
else:
return checkPrefix(strs, l, l + math.ceil((r-l)/4))
改进后的implementation不使用recursion,而是用l
和r
两个pointers,且在checkPrefix
函数只进行prefix的比对。这样的速度快了很多:
def longestCommonPrefix(self, strs: List[str]) -> str:
try:
n = np.min([len(word) for word in strs])
except ValueError:
return ''
if n==0:
return ''
strs = [word[:n] for word in strs]
l = 0
r = n - 1
while l<=r:
mid = math.ceil((l + r)/2)
if checkPrefix(strs, l, mid):
l = mid + 1
else:
r = mid - 1
return strs[0][:r+1]
def checkPrefix(self, strs, l, r):
first = strs[0][l:r+1]
for word in strs:
if first!=word[l:r+1]:
return False
return True
思路很简单:把input的所有词竖着排列起来,从最左边开始,每次比较一个character。
(其实仔细分析一下,vertical scanning应该是最intuitive、最好implement、同时还最快的algorithm了,不知道为什么自己的第一反应是舍近求远去弄最不方便的recursive binary search……)
# deal with edge cases
try:
n = np.min([len(word) for word in strs])
except ValueError:
return ''
if n==0:
return ''
if len(strs)==1:
return strs[0]
strs = [word[:n] for word in strs]
# start scanning
for i in range(n):
first = strs[0][i]
for word in strs[1:]:
if word[i]!=first:
return strs[0][:i]
return strs[0]