Rabin-Karp?
Rabin-Karp 알고리즘은 문자열에서 특정 패턴을 찾는 데 사용되는 효율적인 해시 기반 문자열 검색 알고리즘입니다. 이 알고리즘의 핵심은 해시 함수를 이용해 텍스트와 패턴의 해시 값을 계산하고, 이를 비교하여 패턴을 찾는 방식입니다.
동작 방식:
- 패턴과 텍스트의 첫 번째 부분의 해시 값을 계산합니다.
- 이후 텍스트의 다음 부분을 한 글자씩 이동하면서 해시 값을 업데이트하고, 패턴의 해시 값과 비교합니다.
- 해시 값이 일치하는 경우, 문자열을 실제로 비교하여 패턴이 맞는지 확인합니다.
- 해시 충돌이 발생할 수 있으므로, 해시 값이 일치할 때 실제로 문자열을 비교하는 단계가 필요합니다.
사용 사례:
- 문자열 검색: 긴 텍스트에서 짧은 패턴을 효율적으로 검색하는 데 사용됩니다.
- Plagiarism Detection(표절 검사): 해시 값을 사용해 두 문서가 비슷한지 빠르게 확인할 수 있습니다.
- DNA 서열 분석: 유전자 서열에서 특정 패턴을 찾는 데 사용될 수 있습니다.
JavaScript 예제 코드: Rabin-Karp 알고리즘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function rabinKarp(text, pattern) {
const d = 256; // 알파벳 수
const q = 101; // 소수 (해시 충돌을 줄이기 위해 사용)
const m = pattern.length;
const n = text.length;
let p = 0; // 패턴의 해시 값
let t = 0; // 텍스트의 해시 값
let h = 1;
// h의 값을 계산, h = pow(d, m-1) % q
for (let i = 0; i < m - 1; i++) {
h = (h * d) % q;
}
// 패턴과 텍스트 첫 번째 윈도우의 해시 값을 계산
for (let i = 0; i < m; i++) {
p = (d * p + pattern.charCodeAt(i)) % q;
t = (d * t + text.charCodeAt(i)) % q;
}
// 텍스트에서 패턴을 검색
for (let i = 0; i <= n - m; i++) {
// 해시 값이 같으면 실제 문자열을 비교
if (p === t) {
let j = 0;
for (j = 0; j < m; j++) {
if (text[i + j] !== pattern[j]) {
break;
}
}
if (j === m) {
console.log(`Pattern found at index ${i}`);
}
}
// 다음 윈도우의 해시 값을 계산
if (i < n - m) {
t = (d * (t - text.charCodeAt(i) * h) + text.charCodeAt(i + m)) % q;
if (t < 0) {
t = t + q;
}
}
}
}
// 사용 예시
const text = "GEEKS FOR GEEKS";
const pattern = "GEEK";
rabinKarp(text, pattern); // Output: Pattern found at index 0, 10
설명:
rabinKarp
함수는 텍스트에서 패턴을 검색하며, 각 윈도우의 해시 값을 계산하고 비교하여 일치하는 패턴을 찾습니다.- 해시 충돌이 발생할 수 있으므로 해시 값이 동일할 때는 실제 문자열 비교를 수행합니다.
Rust 예제 코드: Rabin-Karp 알고리즘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
fn rabin_karp(text: &str, pattern: &str) {
let d: i32 = 256;
let q: i32 = 101;
let m = pattern.len();
let n = text.len();
let mut p: i32 = 0; // 패턴의 해시 값
let mut t: i32 = 0; // 텍스트의 해시 값
let mut h: i32 = 1;
// h = pow(d, m-1) % q 계산
for _ in 0..(m-1) {
h = (h * d) % q;
}
// 패턴과 텍스트의 첫 윈도우 해시 값 계산
for i in 0..m {
p = (d * p + pattern.as_bytes()[i] as i32) % q;
t = (d * t + text.as_bytes()[i] as i32) % q;
}
// 텍스트에서 패턴을 검색
for i in 0..=(n - m) {
// 해시 값이 일치하면 실제로 문자열을 비교
if p == t {
if &text[i..i+m] == pattern {
println!("Pattern found at index {}", i);
}
}
// 다음 윈도우의 해시 값을 계산
if i < n - m {
t = (d * (t - (text.as_bytes()[i] as i32 * h)) + text.as_bytes()[i + m] as i32) % q;
if t < 0 {
t = t + q;
}
}
}
}
fn main() {
let text = "GEEKS FOR GEEKS";
let pattern = "GEEK";
rabin_karp(text, pattern); // Output: Pattern found at index 0, 10
}
설명:
- Rust 코드는 JavaScript 코드와 동일한 논리를 따르며, 텍스트와 패턴의 해시 값을 계산하여 패턴을 검색합니다.
- 해시 값이 동일할 때는 실제로 패턴과 텍스트를 비교하여 패턴이 일치하는지 확인합니다.
요약:
Rabin-Karp 알고리즘은 해시 함수를 사용하여 텍스트 내에서 특정 패턴을 찾는 효율적인 방법입니다. 특히, 여러 패턴을 검색하거나 매우 긴 텍스트에서 짧은 패턴을 찾는 경우 유용하게 사용됩니다.
Rabin-Karp Algorithm?
The Rabin-Karp algorithm is an efficient, hash-based string searching algorithm used to find specific patterns within a string. The key idea behind the algorithm is to calculate and compare the hash values of the text and the pattern to efficiently locate the desired pattern.
How it works:
- Compute the hash values of the pattern and the first part of the text.
- Slide over the text one character at a time, updating the hash value for the next part of the text and comparing it with the pattern’s hash.
- If the hash values match, perform an actual string comparison to confirm the pattern.
- Handle potential hash collisions by verifying the actual characters when a hash match is found.
Use Cases:
- String Searching: Efficiently find short patterns in large texts.
- Plagiarism Detection: Quickly compare documents to check for similarities by hashing content.
- DNA Sequence Analysis: Used to identify specific patterns in gene sequences.
JavaScript Example: Rabin-Karp Algorithm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function rabinKarp(text, pattern) {
const d = 256; // Number of characters in the input alphabet
const q = 101; // A prime number to reduce hash collisions
const m = pattern.length;
const n = text.length;
let p = 0; // Hash value for the pattern
let t = 0; // Hash value for text
let h = 1;
// Calculate the value of h = pow(d, m-1) % q
for (let i = 0; i < m - 1; i++) {
h = (h * d) % q;
}
// Calculate the initial hash values for the pattern and the first window of the text
for (let i = 0; i < m; i++) {
p = (d * p + pattern.charCodeAt(i)) % q;
t = (d * t + text.charCodeAt(i)) % q;
}
// Slide the pattern over the text
for (let i = 0; i <= n - m; i++) {
// If hash values match, check the actual characters
if (p === t) {
let j = 0;
for (j = 0; j < m; j++) {
if (text[i + j] !== pattern[j]) {
break;
}
}
if (j === m) {
console.log(`Pattern found at index ${i}`);
}
}
// Calculate hash for next window
if (i < n - m) {
t = (d * (t - text.charCodeAt(i) * h) + text.charCodeAt(i + m)) % q;
if (t < 0) {
t = t + q;
}
}
}
}
// Usage example
const text = "GEEKS FOR GEEKS";
const pattern = "GEEK";
rabinKarp(text, pattern); // Output: Pattern found at index 0, 10
Explanation:
- The
rabinKarp
function scans the text and searches for the pattern by computing hash values and comparing them. - If hash values match, an actual string comparison is done to verify that the pattern exists at that position.
Rust Example: Rabin-Karp Algorithm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
fn rabin_karp(text: &str, pattern: &str) {
let d: i32 = 256;
let q: i32 = 101;
let m = pattern.len();
let n = text.len();
let mut p: i32 = 0; // Hash value for pattern
let mut t: i32 = 0; // Hash value for text
let mut h: i32 = 1;
// Calculate h = pow(d, m-1) % q
for _ in 0..(m-1) {
h = (h * d) % q;
}
// Calculate the initial hash values for the pattern and the first window of the text
for i in 0..m {
p = (d * p + pattern.as_bytes()[i] as i32) % q;
t = (d * t + text.as_bytes()[i] as i32) % q;
}
// Slide the pattern over the text
for i in 0..=(n - m) {
// If hash values match, compare the actual strings
if p == t {
if &text[i..i+m] == pattern {
println!("Pattern found at index {}", i);
}
}
// Calculate the hash value for the next window
if i < n - m {
t = (d * (t - (text.as_bytes()[i] as i32 * h)) + text.as_bytes()[i + m] as i32) % q;
if t < 0 {
t = t + q;
}
}
}
}
fn main() {
let text = "GEEKS FOR GEEKS";
let pattern = "GEEK";
rabin_karp(text, pattern); // Output: Pattern found at index 0, 10
}
Explanation:
- Rust code follows the same logic as the JavaScript code, computing the hash values of both the pattern and the text.
- When a hash match occurs, it performs a direct string comparison to confirm the pattern match.
Summary:
The Rabin-Karp algorithm is an efficient method for searching for a pattern in a text using hash functions. It is particularly useful in scenarios where you need to search for multiple patterns or detect patterns in large bodies of text.