1+ /**
2+ * Implementation of the Boyer-Moore string searching algorithm.
3+ * This algorithm preprocesses the pattern to achieve better than O(n) performance
4+ * on many inputs by using two heuristics:
5+ * 1. Bad Character Rule
6+ * 2. Good Suffix Rule
7+ *
8+ * Time Complexity:
9+ * - Preprocessing: O(m + k) where m is pattern length and k is alphabet size
10+ * - Search: O(mn) worst case, but often performs in O(n/m) in practice
11+ * Space Complexity: O(k) where k is the size of the alphabet
12+ */
13+ public class BoyerMoore {
14+ private static final int NO_OF_CHARS = 256 ;
15+
16+ /**
17+ * Preprocesses the pattern to create the bad character rule array
18+ */
19+ private static int [] createBadCharArray (String pattern ) {
20+ int [] badChar = new int [NO_OF_CHARS ];
21+
22+ // Initialize all occurrences as -1
23+ for (int i = 0 ; i < NO_OF_CHARS ; i ++) {
24+ badChar [i ] = -1 ;
25+ }
26+
27+ // Fill the actual value of last occurrence of a character
28+ for (int i = 0 ; i < pattern .length (); i ++) {
29+ badChar [pattern .charAt (i )] = i ;
30+ }
31+
32+ return badChar ;
33+ }
34+
35+ /**
36+ * Searches for occurrences of pattern in text using Boyer-Moore algorithm
37+ * @param text The text to search in
38+ * @param pattern The pattern to search for
39+ * @return Array of starting indices where pattern is found
40+ */
41+ public static int [] search (String text , String pattern ) {
42+ if (text == null || pattern == null ) {
43+ throw new IllegalArgumentException ("Text and pattern cannot be null" );
44+ }
45+
46+ int [] matches = new int [text .length ()];
47+ int matchCount = 0 ;
48+
49+ int [] badChar = createBadCharArray (pattern );
50+
51+ int shift = 0 ; // Shift of the pattern with respect to text
52+ while (shift <= text .length () - pattern .length ()) {
53+ int j = pattern .length () - 1 ;
54+
55+ // Keep reducing index j of pattern while characters of
56+ // pattern and text are matching at this shift
57+ while (j >= 0 && pattern .charAt (j ) == text .charAt (shift + j )) {
58+ j --;
59+ }
60+
61+ // If the pattern is present at current shift, then j becomes -1
62+ if (j < 0 ) {
63+ matches [matchCount ++] = shift ;
64+ shift += (shift + pattern .length () < text .length ()) ? 1 : 1 ;
65+ } else {
66+ // Shift the pattern so that the bad character in text aligns
67+ // with the last occurrence of it in pattern.
68+ // The max function is used to make sure we get a positive shift.
69+ // We may get a negative shift if the last occurrence of bad
70+ // character in pattern is on the right side of the current character.
71+ shift += Math .max (1 , j - badChar [text .charAt (shift + j )]);
72+ }
73+ }
74+
75+ // Create result array with exact size
76+ int [] result = new int [matchCount ];
77+ System .arraycopy (matches , 0 , result , 0 , matchCount );
78+ return result ;
79+ }
80+
81+ public static void main (String [] args ) {
82+ // Test cases
83+ String text1 = "ABAAABCDABC" ;
84+ String pattern1 = "ABC" ;
85+ System .out .println ("Test Case 1:" );
86+ System .out .println ("Text: " + text1 );
87+ System .out .println ("Pattern: " + pattern1 );
88+ System .out .print ("Pattern found at indices: " );
89+ int [] result1 = search (text1 , pattern1 );
90+ for (int index : result1 ) {
91+ System .out .print (index + " " );
92+ }
93+ System .out .println ("\n " );
94+
95+ String text2 = "AABAACAADAABAAABAA" ;
96+ String pattern2 = "AABA" ;
97+ System .out .println ("Test Case 2:" );
98+ System .out .println ("Text: " + text2 );
99+ System .out .println ("Pattern: " + pattern2 );
100+ System .out .print ("Pattern found at indices: " );
101+ int [] result2 = search (text2 , pattern2 );
102+ for (int index : result2 ) {
103+ System .out .print (index + " " );
104+ }
105+ System .out .println ("\n " );
106+
107+ String text3 = "ABCDEFGHIJKLMNOP" ;
108+ String pattern3 = "XYZ" ;
109+ System .out .println ("Test Case 3:" );
110+ System .out .println ("Text: " + text3 );
111+ System .out .println ("Pattern: " + pattern3 );
112+ System .out .print ("Pattern found at indices: " );
113+ int [] result3 = search (text3 , pattern3 );
114+ if (result3 .length == 0 ) {
115+ System .out .println ("Pattern not found" );
116+ }
117+ }
118+ }
0 commit comments