diff --git a/build.gradle b/build.gradle index 04d375e31c9b..3bf4879fac64 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { repositories { mavenLocal() maven { - url = 'http://repo.maven.apache.org/maven2' + url = 'https://repo.maven.apache.org/maven2' } } diff --git a/src/main/java/com/others/KMP.java b/src/main/java/com/others/KMP.java new file mode 100644 index 000000000000..0123c8fb5a9e --- /dev/null +++ b/src/main/java/com/others/KMP.java @@ -0,0 +1,62 @@ +package com.others; +import java.util.ArrayList; + +/** + * Implementation of the Knuth–Morris–Pratt algorithm + */ +public class KMP { + + /** + * KMPmatcher method finds if any string "needle" is in the string "haystack" and returns the index of its first letter for all occurrencies. + * @param haystack string in which the method is searching + * @param needle string which the method is searching for + * @return an ArrayList of starting indexes of the haystack that matches the searched needle + */ + public static ArrayList KMPmatcher(final String haystack, final String needle) { + final int haystackLength = haystack.length(); + final int needleLength = needle.length(); + final int[] pi = computePrefixFunction(needle); + int matchingLength = 0; + ArrayList startingIndexes = new ArrayList<>(); + for (int i = 0; i < haystackLength; i++) { + while (matchingLength > 0 && haystack.charAt(i) != needle.charAt(matchingLength)) { + matchingLength = pi[matchingLength - 1]; + } + + if (haystack.charAt(i) == needle.charAt(matchingLength)) { + matchingLength++; + } + + if (matchingLength == needleLength) { + startingIndexes.add(i + 1 - needleLength); + matchingLength = pi[matchingLength - 1]; + } + } + return startingIndexes; + } + + /** + * The computePrefixFunction method gets the prefix function of the given string. + * @param P string (this should be the needle in the KNP) + * @return an array of indexes of the given sting where it matches itself + */ + private static int[] computePrefixFunction(final String P) { + final int stringLength = P.length(); + final int[] pi = new int[stringLength]; + pi[0] = 0; + int matchingLength = 0; + for (int i = 1; i < stringLength; i++) { + while (matchingLength > 0 && P.charAt(i) != P.charAt(matchingLength)) { + matchingLength = pi[matchingLength - 1]; + } + + if (P.charAt(i) == P.charAt(matchingLength)) { + matchingLength++; + } + + pi[i] = matchingLength; + + } + return pi; + } +} \ No newline at end of file diff --git a/src/test/java/com/others/KMPTest.java b/src/test/java/com/others/KMPTest.java new file mode 100644 index 000000000000..fc845d80782b --- /dev/null +++ b/src/test/java/com/others/KMPTest.java @@ -0,0 +1,22 @@ +package com.others; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +class KMPTest { + + @Test + void testKMP() { + KMP kmp = new KMP(); + + ArrayList result = new ArrayList<>(); + result.add(0); + result.add(1); + Assertions.assertEquals(result, kmp.KMPmatcher("AAAAABAAABA", "AAAA"), "Incorrect Conversion"); + + ArrayList result2 = new ArrayList<>(); + Assertions.assertEquals(result2, kmp.KMPmatcher("ABABABA", "AAAA"), "Incorrect Conversion"); + } +}