diff --git a/src/main/java/com/thealgorithms/searches/BoyerMoore.java b/src/main/java/com/thealgorithms/searches/BoyerMoore.java new file mode 100644 index 000000000000..92a7d9388539 --- /dev/null +++ b/src/main/java/com/thealgorithms/searches/BoyerMoore.java @@ -0,0 +1,53 @@ +/** + * Boyer-Moore string search algorithm + * Efficient algorithm for substring search. + * https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm + */ +public class BoyerMoore { + + private final int R; + private int[] right; + private String pattern; + + public BoyerMoore(String pat) { + this.pattern = pat; + this.R = 256; // extended ASCII + this.right = new int[R]; + + // Initialize all occurrences as -1 + for (int c = 0; c < R; c++) { + right[c] = -1; + } + + // Fill the actual value of last occurrence of a character + for (int j = 0; j < pat.length(); j++) { + right[pat.charAt(j)] = j; + } + } + + public int search(String text) { + if (pattern.isEmpty()) return 0; + + int m = pattern.length(); + int n = text.length(); + + int skip; + for (int i = 0; i <= n - m; i += skip) { + skip = 0; + for (int j = m - 1; j >= 0; j--) { + char txtChar = text.charAt(i + j); + char patChar = pattern.charAt(j); + if (patChar != txtChar) { + skip = Math.max(1, j - right[txtChar]); + break; + } + } + if (skip == 0) return i; // found + } + return -1; // not found + } + + public static int search(String text, String pattern) { + return new BoyerMoore(pattern).search(text); + } +} diff --git a/src/test/java/com/thealgorithms/searches/BoyerMooreTest.java b/src/test/java/com/thealgorithms/searches/BoyerMooreTest.java new file mode 100644 index 000000000000..0a4414bf9ed8 --- /dev/null +++ b/src/test/java/com/thealgorithms/searches/BoyerMooreTest.java @@ -0,0 +1,56 @@ +package com.thealgorithms.searches; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import com.thealgorithms.searches.BoyerMoore; + +public class BoyerMooreTest { + + @Test + public void testPatternFound() { + BoyerMoore bm = new BoyerMoore("ABCDABD"); + String text = "ABC ABCDAB ABCDABCDABDE"; + int index = bm.search(text); + assertEquals(15, index); + } + + @Test + public void testPatternNotFound() { + BoyerMoore bm = new BoyerMoore("XYZ"); + String text = "ABC ABCDAB ABCDABCDABDE"; + int index = bm.search(text); + assertEquals(-1, index); + } + + @Test + public void testPatternAtBeginning() { + BoyerMoore bm = new BoyerMoore("ABC"); + String text = "ABCDEF"; + int index = bm.search(text); + assertEquals(0, index); + } + + @Test + public void testPatternAtEnd() { + BoyerMoore bm = new BoyerMoore("CDE"); + String text = "ABCDEFGCDE"; + int index = bm.search(text); + assertEquals(7, index); + } + + @Test + public void testEmptyPattern() { + BoyerMoore bm = new BoyerMoore(""); + String text = "Hello world"; + int index = bm.search(text); + assertEquals(0, index); + } + + @Test + public void testStaticSearchMethod() { + String text = "ABCDEFGCDE"; + int index = BoyerMoore.search(text, "CDE"); + assertEquals(7, index); + } +}