Challenge - 5 Problems
Substring Search Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediateOutput of Naive Substring Search
What is the output of this Rust code that searches for all occurrences of a pattern in a text using a naive approach?
DSA Rust
fn naive_search(text: &str, pattern: &str) -> Vec<usize> { let mut positions = Vec::new(); let n = text.len(); let m = pattern.len(); for i in 0..=n - m { if &text[i..i + m] == pattern { positions.push(i); } } positions } fn main() { let text = "abracadabra"; let pattern = "abra"; let result = naive_search(text, pattern); println!("{:?}", result); }
Attempts:
2 left
💡 Hint
Check where the substring "abra" appears exactly in the text "abracadabra".
✗ Incorrect
The pattern "abra" appears at index 0 and again at index 7 in the text. The naive search checks all possible positions and collects these indices.
❓ Predict Output
intermediateOutput of KMP Prefix Table Construction
What is the output vector produced by the prefix function (also called lps array) for the pattern "ababc" in the KMP algorithm?
DSA Rust
fn compute_lps(pattern: &str) -> Vec<usize> { let m = pattern.len(); let mut lps = vec![0; m]; let mut len = 0; let mut i = 1; let chars: Vec<char> = pattern.chars().collect(); while i < m { if chars[i] == chars[len] { len += 1; lps[i] = len; i += 1; } else { if len != 0 { len = lps[len - 1]; } else { lps[i] = 0; i += 1; } } } lps } fn main() { let pattern = "ababc"; let lps = compute_lps(pattern); println!("{:?}", lps); }
Attempts:
2 left
💡 Hint
The lps array stores the length of the longest proper prefix which is also suffix for each prefix of the pattern.
✗ Incorrect
For "ababc", the lps array is [0,0,1,2,0]. This means at index 2, the longest prefix-suffix length is 1, at index 3 it is 2, and so on.
🔧 Debug
advancedIdentify the Error in Rabin-Karp Hash Calculation
What error does this Rust code produce when trying to compute the rolling hash for Rabin-Karp substring search?
DSA Rust
fn rabin_karp_hash(text: &str, pattern_len: usize) -> Vec<u64> { let base = 256u64; let prime = 101u64; let n = text.len(); let mut hashes = Vec::new(); let chars: Vec<u8> = text.bytes().collect(); let mut hash = 0u64; let mut h = 1u64; for _ in 0..pattern_len - 1 { h = (h * base) % prime; } for i in 0..pattern_len { hash = (base * hash + chars[i] as u64) % prime; } hashes.push(hash); for i in pattern_len..n { hash = (base * (hash + prime - chars[i - pattern_len] as u64 * h % prime) + chars[i] as u64) % prime; hashes.push(hash); } hashes } fn main() { let text = "abcdabc"; let hashes = rabin_karp_hash(text, 3); println!("{:?}", hashes); }
Attempts:
2 left
💡 Hint
Look at the subtraction inside the rolling hash update and consider modular arithmetic properties.
✗ Incorrect
The subtraction can produce a negative intermediate value before modulo, which in Rust with unsigned integers wraps around causing incorrect hash values.
🚀 Application
advancedChoosing the Best Algorithm for Large Text and Small Pattern
You have a very large text and a very small pattern to search multiple times. Which substring search algorithm is best suited for this scenario?
Attempts:
2 left
💡 Hint
Consider which algorithm can skip the most characters in the text when the pattern is small.
✗ Incorrect
Boyer-Moore is efficient for small patterns in large texts because it uses bad character and good suffix heuristics to skip ahead, reducing comparisons.
🧠 Conceptual
expertTime Complexity of KMP Algorithm
What is the worst-case time complexity of the Knuth-Morris-Pratt (KMP) substring search algorithm when searching a pattern of length m in a text of length n?
Attempts:
2 left
💡 Hint
KMP preprocesses the pattern and then scans the text efficiently without backtracking.
✗ Incorrect
KMP runs in linear time relative to the sum of the text and pattern lengths, O(n + m), by using the prefix table to avoid re-examining characters.
