最长公共前缀

86 阅读3分钟

这道题目考查的是字符串处理能力,尤其是如何在一组字符串中寻找最长公共前缀。解决这个问题的关键在于比较每个字符串的对应位置的字符,直到在某个位置上找到不匹配的字符为止。这个问题可以通过多种方法解决,下面是几种常见的解题思路:

1. 水平扫描法

这种方法逐个遍历字符串数组中的每个字符串,对于每个字符串,更新最长公共前缀。

  • 开始时,假设第一个字符串是最长公共前缀。
  • 然后逐个与后续的字符串比较,每次比较后,更新最长公共前缀。
  • 如果在某次更新后最长公共前缀为空,说明没有公共前缀,可以直接返回空字符串。
  • 这个过程一直持续到比较完所有字符串。
func longestCommonPrefix(strs []string) string {
	length := len(strs)
	if length < 1 {
		return ""
	}

	prefix := strs[0]
	for i := 1; i < len(strs); i++ {
		//i跟i+1比较
		prefix = samePrefix(prefix, strs[i])
	}

	return prefix
}

//取两个字符串的公共前缀
func samePrefix(s1 string, s2 string) string {
	minLen := len(s1)
	if minLen > len(s2) {
		minLen = len(s2)
	}

	var sameLen int
	for i := 0; i < minLen; i++ {
		if s1[i] == s2[i] {
			sameLen++
		} else {
			break
		}
	}
	return s1[:sameLen]
}

2. 垂直扫描法

这种方法从所有字符串的第一个字符开始比较,然后是所有字符串的第二个字符,依此类推。

  • 比较同一位置上的字符是否相同。
  • 如果在某个位置上字符不全相同,或者某个字符串已经结束,那么到达的位置就是最长公共前缀的长度。
func longestCommonPrefix(strs []string) string {
	length := len(strs)
	if length < 1 {
		return ""
	}

	if strs[0] == "" {
		return ""
	}
	prefix := ""
	//找到长度最短的
	minLen := minLen(strs)

	for i := 0; i < minLen; i++ {
		c := strs[0][i]
		for _, str := range strs {
			//不应该strings.HasPrefix来比,应该按位比,否则会增加复杂度
			if str[i] != c {
				return prefix
			}
		}
		//将c加入前缀
		prefix += string(c)
	}

	return prefix
}

func minLen(strs []string) int {
	minLen := len(strs[0])
	for _, str := range strs[1:] {
		if len(str) < minLen {
			minLen = len(str)
		}
	}
	return minLen
}

3. 分治法

这种方法将原问题分解为更小的问题,然后将小问题的答案组合起来解决原问题。

  • 将字符串数组分成两部分,分别求出左半部分和右半部分的最长公共前缀,然后找出这两个前缀的公共前缀。

从两个字符串求公共前缀,推演到多个字符串求公共前缀

func longestCommonPrefix(strs []string) string {
	if len(strs) < 1 {
		return ""
	}
	
	return getPrefix(strs, 0, len(strs)-1)
}

func getPrefix(strs []string, left, right int) string {
	if right <= left {
		return strs[left]
	}

	leftPrefix := getPrefix(strs, left, left+(right-left)/2)
	rightPrefix := getPrefix(strs, left+(right-left)/2+1, right)
	return samePrefix(leftPrefix, rightPrefix)
}

//取两个字符串的公共前缀
func samePrefix(s1 string, s2 string) string {
	minLen := len(s1)
	if minLen > len(s2) {
		minLen = len(s2)
	}

	var sameLen int
	for i := 0; i < minLen; i++ {
		if s1[i] == s2[i] {
			sameLen++
		} else {
			break
		}
	}
	return s1[:sameLen]
}

4. 二分查找法

这种方法利用二分查找确定最长公共前缀的最大可能长度。

  • 首先,找出所有字符串中长度最短的那个,并将其长度作为二分查找的上界。
  • 然后通过二分查找,在这个长度范围内寻找最长公共前缀。
  • 每次二分查找时,检查所有字符串的前mid(left和right的中间值)个字符是否相同,根据检查结果调整搜索范围。