LeetCode 14.最长公共前缀--Python3

文章目录

    • 问题描述
    • 示例
    • 解法一:水平扫描法
    • 解法二:分治法
    • 解法三:二分查找法

问题描述

编写一个函数来查找字符串数组中的最长公共前缀
如果不存在公共前缀,返回空字符串 “”

示例

输入:[“flower”,“flow”,“flight”]
输出:“fl”

解法一:水平扫描法

算法描述:
首先,将列表中的字符串按照长度重新排序,然后依次遍历字符串 [ S 1 … S n ] \left[S_{1} \ldots S_{n}\right] [S1Sn],首先求 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(S1Sn)=LCP(LCP(LCP(S1,S2),S3),Sn)

LeetCode 14.最长公共前缀--Python3_第1张图片

图 1. 查找最长公共前缀 (水平扫描法)

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(S1Sn)=LCP(LCP(S1Sk),LCP(Sk+1Sn))

,其中 LCP ⁡ ( S 1 … S n ) \operatorname{LCP}\left(S_{1} \ldots S_{n}\right) LCP(S1Sn)是字符串 [ S 1 … S n ] \left[S_{1} \ldots S_{n}\right] [S1Sn]的最长公共前缀, 1 < k < n 11<k<n
为了应用上述的结论,我们使用分治的技巧,将原问题 L C P ( S i ⋯ S j ) L C P\left(S_{i} \cdots S_{j}\right) LCP(SiSj)分成两个子问题 L C P ( S i ⋯ S m i d ) L C P\left(S_{i} \cdots S_{m i d}\right) LCP(SiSmid) 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 最长公共前缀就是原问题的解。
LeetCode 14.最长公共前缀--Python3_第2张图片

图 2. 查找最长公共前缀的分治方法

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) (0minLen),其中 minLen 是输入数据中最短的字符串的长度,同时也是答案的最长可能长度。 每一次将查找区间一分为二,算法进行的过程中一共会出现两种可能情况:

  • S[1…mid] 不是所有串的公共前缀。 这表明该前缀加上mid后面的字符也一定不是公共前缀,于是我们就可以丢弃后半个查找区间。

  • S[1…mid] 是所有串的公共前缀。 这表示该前缀加上mid后面的字符有可能也是公共前缀,因为我们要找最长的公共前缀,所以我们将mid后的字符附加在S[1…mid]后继续进行匹配。
    LeetCode 14.最长公共前缀--Python3_第3张图片

图 3. 使用二分查找法寻找最长公共前缀

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]

你可能感兴趣的:(LeetCode)