Skip to main content

Z Algorithm

In computer science, the Z-Algorithm is an efficient linear-time algorithm used for pattern matching in strings. It computes an array Z for a given string S, where Z[i] contains the length of the longest substring starting from S[i] that is also a prefix of S. The Z-Algorithm is widely used in competitive programming and string matching applications.

Definition:

The Z-Algorithm computes an array Z for a string S such that Z[i] contains the length of the longest substring starting from S[i] that is also a prefix of S. It is an efficient method to solve pattern matching problems.

Explanation:

Given a string S of length n, the Z-array is computed where Z[i] is the length of the longest substring starting from S[i] that matches the prefix of S. The algorithm runs in O(n) time and is used in various string matching applications.

Code Implementation

def calculate_z(S):
"""Calculates the Z-array for a given string S.

Args:
S: The input string.

Returns:
A list where each element i contains the length of the longest substring
starting from S[i] which is also a prefix of S.
"""
Z = [0] * len(S)
L, R, K = 0, 0, 0
for i in range(1, len(S)):
if i > R:
L, R = i, i
while R < len(S) and S[R] == S[R - L]:
R += 1
Z[i] = R - L
R -= 1
else:
K = i - L
if Z[K] < R - i + 1:
Z[i] = Z[K]
else:
L = i
while R < len(S) and S[R] == S[R - L]:
R += 1
Z[i] = R - L
R -= 1
return Z

Code Implementation (C++):

#include <iostream>
#include <vector>
using namespace std;

vector<int> calculate_z(string S) {
int n = S.length();
vector<int> Z(n);
int L = 0, R = 0, K;

for (int i = 1; i < n; i++) {
if (i > R) {
L = R = i;
while (R < n && S[R] == S[R - L])
R++;
Z[i] = R - L;
R--;
} else {
K = i - L;
if (Z[K] < R - i + 1) {
Z[i] = Z[K];
} else {
L = i;
while (R < n && S[R] == S[R - L])
R++;
Z[i] = R - L;
R--;
}
}
}
return Z;
}

int main() {
string S = "aabcaabxaaaz";
vector<int> Z = calculate_z(S);

cout << "Z-array: ";
for (int z : Z)
cout << z << " ";
cout << endl;

return 0;
}

Code Implementation (Java):

import java.util.Arrays;

public class ZAlgorithm {

public static int[] calculate_z(String S) {
int n = S.length();
int[] Z = new int[n];
int L = 0, R = 0, K;

for (int i = 1; i < n; i++) {
if (i > R) {
L = R = i;
while (R < n && S.charAt(R) == S.charAt(R - L))
R++;
Z[i] = R - L;
R--;
} else {
K = i - L;
if (Z[K] < R - i + 1) {
Z[i] = Z[K];
} else {
L = i;
while (R < n && S.charAt(R) == S.charAt(R - L))
R++;
Z[i] = R - L;
R--;
}
}
}
return Z;
}

public static void main(String[] args) {
String S = "aabcaabxaaaz";
int[] Z = calculate_z(S);

System.out.println("Z-array: " + Arrays.toString(Z));
}
}

Explanation of the Code:

  • calculate_z: This function computes the Z-array for the given string S. The Z-array holds the length of the longest substring starting from index i that matches the prefix of the string.
  • The Z-values are calculated using two pointers, L and R, which define the current window where a match with the prefix exists.

Example Usage:

For the string S = "aabcaabxaaaz", the computed Z-array is [0, 1, 0, 0, 3, 1, 0, 0, 2, 1, 0, 0].

Applications in Competitive Programming

Pattern Matching:

The Z-algorithm is used to search for occurrences of a pattern in a text by concatenating the pattern and text with a unique separator and computing the Z-array.

String Matching:

Efficiently find all occurrences of a pattern in a string, which is useful in solving problems like finding periodicities in strings or solving DNA sequence matching.

Prefix-Suffix Problems:

Can be used to find all prefixes of a string that are also suffixes, which is helpful in problems like finding palindromes and string periodicity.