Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions src/main/java/com/thealgorithms/strings/Zalgorithm.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.thealgorithms.strings;

import java.util.ArrayList;
import java.util.List;

/**
* Z-algorithm implementation to find all occurrences of a pattern in a text.
*/
public final class Zalgorithm {
private Zalgorithm() {
}

/**
* Finds occurrences of a pattern in a text using Z-algorithm.
*
* @param text the input text in which we are searching the pattern
* @param pattern the pattern to search for
* @return a list of indices where the pattern occurs in the text
*/
public static List<Integer> findPatternOccurrences(String text, String pattern) {
String combined = pattern + "$" + text;
int[] zArray = calculateZ(combined);
List<Integer> occurrences = new ArrayList<>();
int patternLength = pattern.length();

for (int i = patternLength + 1; i < zArray.length; i++) {
if (zArray[i] >= patternLength) {
occurrences.add(i - patternLength - 1);
}
}
return occurrences;
}

/**
* Helper method to calculate Z-array for a given string.
*
* @param s the input string
* @return the Z-array where Z[i] is the length of the longest substring
* starting from i that is also a prefix of s
*/
private static int[] calculateZ(String s) {
int n = s.length();
int[] z = new int[n];
int l = 0, r = 0;

for (int i = 1; i < n; i++) {
if (i <= r) {
z[i] = Math.min(r - i + 1, z[i - l]);
}
while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) {
z[i]++;
}
if (i + z[i] - 1 > r) {
l = i;
r = i + z[i] - 1;
}
}
return z;
}
}
36 changes: 36 additions & 0 deletions src/test/java/com/thealgorithms/strings/ZalgorithmTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.thealgorithms.strings;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.Test;

public class ZalgorithmTest {

/**
* Test 1:
* Pattern: "abc", Text: "ababcabcabc"
* Expected: [2, 5, 8]
*/
@Test
public void testFindPatternOccurrences() {
String text = "ababcabcabc";
String pattern = "abc";
List<Integer> expected = Arrays.asList(2, 5, 8);
assertEquals(expected, Zalgorithm.findPatternOccurrences(text, pattern));
}

/**
* Test 2:
* Pattern: "aa", Text: "aaaaaa"
* Expected: [0, 1, 2, 3, 4]
*/
@Test
public void testFindPatternOccurrencesRepeated() {
String text = "aaaaaa";
String pattern = "aa";
List<Integer> expected = Arrays.asList(0, 1, 2, 3, 4);
assertEquals(expected, Zalgorithm.findPatternOccurrences(text, pattern));
}
}
Loading