package com.interview.string;
import java.util.ArrayList;
import java.util.List;
/**
* Date 10/31/2015
* @author Tushar Roy
*
* Z algorithm to pattern matching
*
* Time complexity - O(n + m)
* Space complexity - O(n + m)
*
* http://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/
* http://www.utdallas.edu/~besp/demo/John2010/z-algorithm.htm
*/
public class ZAlgorithm {
private int[] calculateZ(char input[]) {
int Z[] = new int[input.length];
int left = 0;
int right = 0;
for(int k = 1; k < input.length; k++) {
if(k > right) {
left = right = k;
while(right < input.length && input[right] == input[right - left]) {
right++;
}
Z[k] = right - left;
right--;
} else {
//we are operating inside box
int k1 = k - left;
//if value does not stretches till right bound then just copy it.
if(Z[k1] < right - k + 1) {
Z[k] = Z[k1];
} else { //otherwise try to see if there are more matches.
left = k;
while(right < input.length && input[right] == input[right - left]) {
right++;
}
Z[k] = right - left;
right--;
}
}
}
return Z;
}
/**
* Returns list of all indices where pattern is found in text.
*/
public List<Integer> matchPattern(char text[], char pattern[]) {
char newString[] = new char[text.length + pattern.length + 1];
int i = 0;
for(char ch : pattern) {
newString[i] = ch;
i++;
}
newString[i] = '$';
i++;
for(char ch : text) {
newString[i] = ch;
i++;
}
List<Integer> result = new ArrayList<>();
int Z[] = calculateZ(newString);
for(i = 0; i < Z.length ; i++) {
if(Z[i] == pattern.length) {
result.add(i - pattern.length - 1);
}
}
return result;
}
public static void main(String args[]) {
String text = "aaabcxyzaaaabczaaczabbaaaaaabc";
String pattern = "aaabc";
ZAlgorithm zAlgorithm = new ZAlgorithm();
List<Integer> result = zAlgorithm.matchPattern(text.toCharArray(), pattern.toCharArray());
result.forEach(System.out::println);
}
}