📌  相关文章
📜  使用 Z 算法查找数组 A 中给定数组 B 每次出现的起始索引(1)

📅  最后修改于: 2023-12-03 14:49:47.681000             🧑  作者: Mango

使用 Z 算法查找数组 A 中给定数组 B 每次出现的起始索引

介绍

Z 算法是一种在字符串匹配中用于快速计算模式串与主串的匹配程度的算法。它可以用于查找一个数组中给定数组每次出现的起始索引。这种算法的时间复杂度为 O(N+M),其中 N 是数组 A 的长度,M 是数组 B 的长度。

实现步骤
  1. 将数组 B 连接到数组 A 的后面,中间用特殊字符(例如 "$")分隔。
  2. 定义一个大小等于数组 A 的长度的数组 Z,用于保存每个位置 i 开始的子串与数组 B 的最长匹配长度。
  3. 初始化左右边界 L 和 R,其中 L=0,R=0。
  4. 对于每个 i,计算 Z[i] 的值:
  • 如果 i > R,说明之前没有匹配到子串与数组 B 的匹配长度大于等于 B 的长度的情况,需要使用传统方法进行匹配。将 L 和 R 设置为 i,并计算 Z[i] 的值。
  • 如果 i <= R,说明存在之前匹配到子串与数组 B 的匹配长度大于等于 B 的长度的情况,可以利用之前的计算结果进行匹配。将 j = i-L,如果 Z[j] <= R-i,则说明 Z[j] 的值在当前边界内,可以直接使用,否则需要从 R+1 开始重新匹配。
  1. 如果 Z[i] 等于数组 B 的长度,表示数组 B 在数组 A 中的起始索引为 i-L-1。

以下是使用 Python 实现的示例代码:

def z_algorithm(A, B):
    """
    使用 Z 算法查找数组 A 中给定数组 B 的每次出现的起始索引
    
    Args:
        A: 主数组
        B: 给定数组
    
    Returns:
        result: 数组 B 在数组 A 中的起始索引组成的列表
    """
    # 将数组 B 连接到数组 A 的后面,中间用特殊字符(例如 "$")分隔
    C = B + ['$'] + A
    
    # 定义一个大小等于数组 A 的长度的数组 Z
    Z = [0] * len(C)
    
    # 初始化左右边界
    L = 0
    R = 0
    
    result = []
    
    # 计算 Z[i] 的值
    for i in range(1, len(C)):
        if i > R:
            # 传统匹配方法
            L = R = i
            while R < len(C) and C[R-L] == C[R]:
                R += 1
            Z[i] = R - L
            
            if Z[i] == len(B):
                result.append(i - len(B) - 1)
        else:
            j = i - L
            if Z[j] <= R - i:
                # 直接使用之前的计算结果
                Z[i] = Z[j]
            else:
                # 重新匹配
                L = i
                while R < len(C) and C[R-L] == C[R]:
                    R += 1
                Z[i] = R - L
                
                if Z[i] == len(B):
                    result.append(i - len(B) - 1)
    
    return result
示例
A = [1, 2, 3, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
B = [2, 3, 4]

result = z_algorithm(A, B)
print(result)  # 输出: [1, 5, 9]

以上示例中,数组 B 在数组 A 中的起始索引为 1, 5, 9。