Go猜想录
大道至简,悟者天成
真实面试案例分析(下)

摘要

  • 字符串查找strStr
    • 为什么不需要学KMP算法
    • Rabin-karp算法与哈希函数Hash Function
  • 为什么我们不需要学习贪心法
  • 三个你必须知道的语言知识
    1. 如何判断两个字符串是否相等
    2. 如何遍历字符串
    3. null和 "" 有什么区别
  • 十个你必须掌握的字符串处理函数

13 · 字符串查找

O(n^2) Best Practise

/**
 * @param source: 
 * @param target: 
 * @return: return the index
 */
func StrStr(haystack string, needle string) int {
	// 在剩余长度不足时直接退出,是否加1可以代特殊值
	for i := 0; i < len(haystack)-len(needle)+1; i++ {
		equal := true
		// 写 for 循环比较,不需要额外空间
		for j := 0; j < len(needle); j++ {
			if haystack[i+j] != needle[j] {
				equal = false
				break
			}
		}
		if equal {
			return i
		}
	}
	return -1
}

594 · 字符串查找 II

Robin karp
时间复杂度 O(n+m)

  1. 哈希函数
    • 通过将字符串转换为一个基于位置的数值来计算哈希值。为了避免溢出,这里使用了模运算(模数选择为101,一个质数)。
    • h 是一个辅助变量,用于调整窗口哈希值的计算。
  2. 初始哈希值计算
    • 计算 needlehaystack 的初始窗口的哈希值。窗口大小等于 needle 的长度。
  3. 滑动窗口
    • 遍历 haystack,对每个窗口的哈希值进行比较。如果两个哈希值相等,则逐字符检查两个字符串是否完全匹配。
    • 如果哈希值不同,直接计算下一个窗口的哈希值,而不必重新计算整个窗口,从而提高效率。
  4. 哈希冲突
    • 虽然哈希值相同并不一定意味着两个字符串相同(存在哈希冲突),但对于大多数场景,这种算法是有效的。当哈希值相等时,逐字符比较确保准确性。

Rabin-Karp算法特别适合用于在大文本中搜索多个模式,因为哈希值的比较通常比逐字符比较更快。

func StrStr2(haystack string, needle string) int {
	// 如果 needle 是空字符串,返回0
	if len(needle) == 0 {
		return 0
	}

	// 如果 haystack 的长度小于 needle 的长度,返回-1
	if len(haystack) < len(needle) {
		return -1
	}

	// 定义哈希相关的常量
	const base = 256
	const mod = 101 // 选择一个合适的质数作为模数

	// 计算 needle 的哈希值
	needleHash := 0
	haystackHash := 0
	h := 1

    // 为了防止乘出来的数太大,边乘边模
	for i := 0; i < len(needle)-1; i++ {
		h = (h * base) % mod
	}

	for i := 0; i < len(needle); i++ {
		needleHash = (base*needleHash + int(needle[i])) % mod
		haystackHash = (base*haystackHash + int(haystack[i])) % mod
	}

	// 滑动窗口进行匹配
	for i := 0; i <= len(haystack)-len(needle); i++ {
		// 如果哈希值相同,进一步检查实际的字符串
		if needleHash == haystackHash {
			match := true
			for j := 0; j < len(needle); j++ {
				if haystack[i+j] != needle[j] {
					match = false
					break
				}
			}
			if match {
				return i
			}
		}

		// 计算下一个窗口的哈希值
		if i < len(haystack)-len(needle) {
			haystackHash = (base*(haystackHash-int(haystack[i])*h) + int(haystack[i+len(needle)])) % mod
			if haystackHash < 0 {
				haystackHash += mod
			}
		}
	}

	return -1
}

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。