Skip to content

Commit a205585

Browse files
committed
add ZAlgorithm for linear pattern matching
1 parent 5e9d9f7 commit a205585

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package com.thealgorithms.strings;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Z Algorithm for pattern matching in linear time
8+
*
9+
* The Z-algorithm computes, for each position i in a string,
10+
* the length of the longest substring starting at i which is
11+
* also a prefix of the string.
12+
*
13+
* Time Complexity: O(n + m) where n is text length, m is pattern length
14+
* Space Complexity: O(n + m)
15+
*
16+
* @author Your Name
17+
*/
18+
public final class ZAlgorithm {
19+
private ZAlgorithm() {
20+
}
21+
22+
/**
23+
* Finds all occurrences of pattern in text using Z-algorithm
24+
*
25+
* @param text the text to search in
26+
* @param pattern the pattern to search for
27+
* @return list of starting indices where pattern occurs
28+
* @throws IllegalArgumentException if text or pattern is null
29+
*/
30+
public static List<Integer> search(String text, String pattern) {
31+
if (text == null || pattern == null) {
32+
throw new IllegalArgumentException("Text and pattern cannot be null");
33+
}
34+
35+
List<Integer> result = new ArrayList<>();
36+
37+
if (pattern.isEmpty() || pattern.length() > text.length()) {
38+
return result;
39+
}
40+
41+
// Concatenate pattern and text with a separator
42+
String combined = pattern + "$" + text;
43+
int[] zArray = computeZArray(combined);
44+
45+
int patternLength = pattern.length();
46+
47+
// Find positions where Z-value equals pattern length
48+
for (int i = patternLength + 1; i < combined.length(); i++) {
49+
if (zArray[i] == patternLength) {
50+
result.add(i - patternLength - 1);
51+
}
52+
}
53+
54+
return result;
55+
}
56+
57+
/**
58+
* Computes the Z-array for the given string
59+
* Z[i] = length of longest substring starting at i which is also a prefix
60+
*
61+
* @param str input string
62+
* @return Z-array
63+
*/
64+
private static int[] computeZArray(String str) {
65+
int n = str.length();
66+
int[] zArray = new int[n];
67+
68+
int left = 0;
69+
int right = 0;
70+
71+
for (int i = 1; i < n; i++) {
72+
// If i is outside the current Z-box, compute Z[i] from scratch
73+
if (i > right) {
74+
left = right = i;
75+
76+
while (right < n && str.charAt(right - left) == str.charAt(right)) {
77+
right++;
78+
}
79+
80+
zArray[i] = right - left;
81+
right--;
82+
} else {
83+
// i is inside the current Z-box
84+
int k = i - left;
85+
86+
// If Z[k] is less than remaining interval, reuse it
87+
if (zArray[k] < right - i + 1) {
88+
zArray[i] = zArray[k];
89+
} else {
90+
// Start from right boundary and try to extend
91+
left = i;
92+
93+
while (right < n && str.charAt(right - left) == str.charAt(right)) {
94+
right++;
95+
}
96+
97+
zArray[i] = right - left;
98+
right--;
99+
}
100+
}
101+
}
102+
103+
return zArray;
104+
}
105+
106+
/**
107+
* Computes only the Z-array for a given string
108+
* Useful for other applications beyond pattern matching
109+
*
110+
* @param str input string
111+
* @return Z-array where Z[i] is length of longest prefix match at position i
112+
* @throws IllegalArgumentException if string is null
113+
*/
114+
public static int[] getZArray(String str) {
115+
if (str == null) {
116+
throw new IllegalArgumentException("String cannot be null");
117+
}
118+
return computeZArray(str);
119+
}
120+
}

src/test/java/com/thealgorithms/strings/ZAlgorithmTest.java

Whitespace-only changes.

0 commit comments

Comments
 (0)