注:你的关注,点赞,评论让我不停更新
KMP(Knuth - Morris - Pratt)算法与字符串哈希
KMP 算法
-
原理:KMP 算法用于解决字符串匹配问题,其核心是利用已经匹配过的信息,避免在匹配过程中进行不必要的回溯。通过计算部分匹配表(也称为前缀表,
next
数组),记录模式串中每个位置之前的子串的最长公共前后缀长度,从而在匹配失败时能够快速移动模式串。 -
代码示例:
def get_next(pattern):
m = len(pattern)
next_arr = [0] * m
j = 0
for i in range(1, m):
while j > 0 and pattern[i] != pattern[j]:
j = next_arr[j - 1]
if pattern[i] == pattern[j]:
j += 1
next_arr[i] = j
return next_arr
def kmp_search(text, pattern):
n = len(text)
m = len(pattern)
next_arr = get_next(pattern)
j = 0
for i in range(n):
while j > 0 and text[i] != pattern[j]:
j = next_arr[j - 1]
if text[i] == pattern[j]:
j += 1
if j == m:
return i - m + 1
return -1
text = "ABABDABACDABABCABAB"
pattern = "ABABCABAB"
print(kmp_search(text, pattern))
-
蓝桥杯应用:在蓝桥杯题目中,当遇到字符串匹配相关问题,如在一个长文本中查找某个特定模式串的出现位置或次数时,KMP 算法能显著提高效率。例如,给定一篇文章和一个关键词,统计关键词在文章中出现的次数。
字符串哈希
-
原理:将字符串映射为一个整数,通过比较整数是否相等来判断字符串是否相等。常见的做法是使用多项式哈希,将字符串看作一个多项式,选择合适的基数和模数进行计算。
-
代码示例:
def string_hash(s, base=131, mod=10**9 + 7):
hash_val = 0
for char in s:
hash_val = (hash_val * base + ord(char)) % mod
return hash_val
s1 = "abc"
s2 = "abc"
print(string_hash(s1) == string_hash(s2))
-
蓝桥杯应用:可用于快速判断两个字符串是否相等,在处理大量字符串比较的问题中很有用。比如,判断多个字符串中是否存在重复的字符串,或者在一个字符串数组中查找与给定字符串相等的字符串。
Manacher 算法
-
原理:Manacher 算法用于解决最长回文子串问题,它通过添加特殊字符将字符串的长度变为奇数,同时利用回文串的对称性,避免了对每个位置的重复扩展,从而将时间复杂度优化到 (O(n))。
-
代码示例:
def manacher(s):
t = '#'.join('^{}$'.format(s))
n = len(t)
p = [0] * n
c = r = 0
for i in range(1, n - 1):
i_mirror = 2 * c - i
if r > i:
p[i] = min(r - i, p[i_mirror])
else:
p[i] = 0
while t[i + 1 + p[i]] == t[i - 1 - p[i]]:
p[i] += 1
if i + p[i] > r:
c = i
r = i + p[i]
max_len = center_index = 0
for i in range(1, n - 1):
if p[i] > max_len:
max_len = p[i]
center_index = i
start = (center_index - max_len) // 2
return s[start: start + max_len]
s = "babad"
print(manacher(s))
-
蓝桥杯应用:当题目要求找出给定字符串中的最长回文子串时,Manacher 算法是首选。例如,判断一个字符串经过某些操作后能否变成回文串,或者求一个字符串中所有回文子串的长度总和等问题。
0 - 1 Trie 树
-
原理:0 - 1 Trie 树是一种特殊的 Trie 树,用于处理二进制数。它的每个节点有两个子节点,分别表示 0 和 1。常用于解决与二进制位运算相关的问题,如求最大异或和。
-
代码示例:
class TrieNode:
def __init__(self):
self.children = [None] * 2
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, num):
node = self.root
for i in range(31, -1, -1):
bit = (num >> i) & 1
if not node.children[bit]:
node.children[bit] = TrieNode()
node = node.children[bit]
def query_max_xor(self, num):
node = self.root
xor_val = 0
for i in range(31, -1, -1):
bit = (num >> i) & 1
toggled_bit = 1 - bit
if node.children[toggled_bit]:
xor_val |= (1 << i)
node = node.children[toggled_bit]
else:
node = node.children[bit]
return xor_val
trie = Trie()
nums = [3, 10, 5, 25, 2, 8]
for num in nums:
trie.insert(num)
max_xor = 0
for num in nums:
max_xor = max(max_xor, trie.query_max_xor(num))
print(max_xor)
-
蓝桥杯应用:在蓝桥杯题目中,当遇到与二进制异或运算相关的问题,如求数组中两个元素的最大异或和、在一组二进制数中找到满足特定异或条件的数对时,0 - 1 Trie 树可以高效地解决这些问题。