Skip to content

Commit 8ea5c8c

Browse files
feat: Add KMP Substring Search Algorithm (#231)
1 parent a823656 commit 8ea5c8c

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

README.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,78 @@ public class StringToDateSnippet {
20502050
}
20512051
```
20522052

2053+
2054+
### KMP Substring Search Algorithm
2055+
2056+
```java
2057+
public class KMPSubstringSearchSnippet {
2058+
2059+
/**
2060+
* Implements the Knuth-Morris-Pratt (KMP) algorithm to find the index of the first occurrence of a substring in a given text.
2061+
*
2062+
* @param text The text in which the substring is to be searched.
2063+
* @param pattern The substring pattern to search for.
2064+
* @return The index of the first occurrence of the pattern in the text, or -1 if the pattern is not found.
2065+
*/
2066+
public static int kmpSearch(String text, String pattern) {
2067+
if (pattern == null || pattern.length() == 0) {
2068+
return 0; // Trivial case: empty pattern
2069+
}
2070+
2071+
int[] lps = computeLPSArray(pattern);
2072+
int i = 0; // index for text
2073+
int j = 0; // index for pattern
2074+
2075+
while (i < text.length()) {
2076+
if (pattern.charAt(j) == text.charAt(i)) {
2077+
i++;
2078+
j++;
2079+
}
2080+
2081+
if (j == pattern.length()) {
2082+
return i - j; // Found pattern at index (i - j)
2083+
} else if (i < text.length() && pattern.charAt(j) != text.charAt(i)) {
2084+
if (j != 0) {
2085+
j = lps[j - 1]; // Use the LPS array to skip characters
2086+
} else {
2087+
i++; // If no match and j is 0, move to the next character in text
2088+
}
2089+
}
2090+
}
2091+
return -1; // Pattern not found
2092+
}
2093+
2094+
/**
2095+
* Computes the LPS (Longest Prefix Suffix) array for the pattern, which indicates the longest proper prefix which is also a suffix.
2096+
*
2097+
* @param pattern The pattern for which the LPS array is to be computed.
2098+
* @return The LPS array.
2099+
*/
2100+
private static int[] computeLPSArray(String pattern) {
2101+
int length = 0;
2102+
int i = 1;
2103+
int[] lps = new int[pattern.length()];
2104+
lps[0] = 0; // LPS for the first character is always 0
2105+
2106+
while (i < pattern.length()) {
2107+
if (pattern.charAt(i) == pattern.charAt(length)) {
2108+
length++;
2109+
lps[i] = length;
2110+
i++;
2111+
} else {
2112+
if (length != 0) {
2113+
length = lps[length - 1]; // Fall back to the previous LPS value
2114+
} else {
2115+
lps[i] = 0;
2116+
i++;
2117+
}
2118+
}
2119+
}
2120+
return lps;
2121+
}
2122+
}
2123+
```
2124+
20532125
## Thread
20542126

20552127
### Thread Pool
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2017-2024 Ilkka Seppälä
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package string;
26+
27+
/**
28+
* KmpSubstringSearchSnippet.
29+
*/
30+
31+
public class KmpSubstringSearchSnippet {
32+
33+
/**
34+
* Implements the Knuth-Morris-Pratt (KMP) algorithm to find the of a substring.
35+
*
36+
* @param text The text in which the substring is to be searched.
37+
* @param pattern The substring pattern to search for.
38+
* @return The index of the first occurrence, or -1 if the pattern is not found.
39+
*/
40+
public static int kmpSearch(String text, String pattern) {
41+
if (pattern == null || pattern.length() == 0) {
42+
return 0; // Trivial case: empty pattern
43+
}
44+
45+
int[] lps = computeLpsArray(pattern);
46+
int i = 0; // index for text
47+
int j = 0; // index for pattern
48+
49+
while (i < text.length()) {
50+
if (pattern.charAt(j) == text.charAt(i)) {
51+
i++;
52+
j++;
53+
}
54+
55+
if (j == pattern.length()) {
56+
return i - j; // Found pattern at index (i - j)
57+
} else if (i < text.length() && pattern.charAt(j) != text.charAt(i)) {
58+
if (j != 0) {
59+
j = lps[j - 1]; // Use the LPS array to skip characters
60+
} else {
61+
i++; // If no match and j is 0, move to the next character in text
62+
}
63+
}
64+
}
65+
return -1; // Pattern not found
66+
}
67+
68+
/**
69+
* Computes the LPS (Longest Prefix Suffix) array, which indicates the longest proper prefix.
70+
*
71+
* @param pattern The pattern for which the LPS array is to be computed.
72+
* @return The LPS array.
73+
*/
74+
private static int[] computeLpsArray(String pattern) {
75+
int length = 0;
76+
int i = 1;
77+
int[] lps = new int[pattern.length()];
78+
lps[0] = 0; // LPS for the first character is always 0
79+
80+
while (i < pattern.length()) {
81+
if (pattern.charAt(i) == pattern.charAt(length)) {
82+
length++;
83+
lps[i] = length;
84+
i++;
85+
} else {
86+
if (length != 0) {
87+
length = lps[length - 1]; // Fall back to the previous LPS value
88+
} else {
89+
lps[i] = 0;
90+
i++;
91+
}
92+
}
93+
}
94+
return lps;
95+
}
96+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2017-2024 Ilkka Seppälä
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package string;
26+
27+
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
29+
import org.junit.jupiter.api.Test;
30+
31+
/*
32+
* Tests for 30 Seconds of Java code library
33+
*
34+
*/
35+
class KmpSubstringSearchSnippetTest {
36+
37+
/**
38+
* Tests for {@link KmpSubstringSearchSnippet#kmpSearch(String, String)}.
39+
*/
40+
@Test
41+
void testKmpSearch() {
42+
// Test cases for KMP substring search
43+
assertEquals(6, KmpSubstringSearchSnippet.kmpSearch("abxabcabcaby", "abcaby"));
44+
assertEquals(7, KmpSubstringSearchSnippet.kmpSearch("subash pandey", "pandey"));
45+
assertEquals(-1, KmpSubstringSearchSnippet.kmpSearch("abcd", "e"));
46+
assertEquals(0, KmpSubstringSearchSnippet.kmpSearch("aaaaa", "a"));
47+
assertEquals(2, KmpSubstringSearchSnippet.kmpSearch("abcdabcd", "cdab"));
48+
}
49+
}

0 commit comments

Comments
 (0)