Skip to content

Commit

Permalink
Add problem 1910: Remove All Occurrences of a Substring
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed May 9, 2024
1 parent 3c7ba2a commit 330a572
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,7 @@ pub mod problem_1903_largest_odd_number_in_string;
pub mod problem_1904_the_number_of_full_rounds_you_have_played;
pub mod problem_1906_minimum_absolute_difference_queries;
pub mod problem_1909_remove_one_element_to_make_the_array_strictly_increasing;
pub mod problem_1910_remove_all_occurrences_of_a_substring;
pub mod problem_1911_maximum_alternating_subsequence_sum;
pub mod problem_1913_maximum_product_difference_between_two_pairs;
pub mod problem_1915_number_of_wonderful_substrings;
Expand Down
83 changes: 83 additions & 0 deletions src/problem_1910_remove_all_occurrences_of_a_substring/kmp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
pub struct Solution;

// ------------------------------------------------------ snip ------------------------------------------------------ //

impl Solution {
fn compute_kmp_table(s: &[u8]) -> Box<[u16]> {
let mut result = vec![0; s.len()].into_boxed_slice();
let mut matched = 0;
let mut i = 1;

while let Some(&c) = s.get(i) {
loop {
if c == s[matched] {
matched += 1;
result[i] = matched as _;

break;
} else if let Some(&next_matched) = result.get(matched.wrapping_sub(1)) {
matched = usize::from(next_matched);
} else {
break;
}
}

i += 1;
}

result
}

pub fn remove_occurrences(s: String, part: String) -> String {
let mut s = s.into_bytes();
let part = part.as_bytes();
let kmp_table = Self::compute_kmp_table(part);
let mut matched = 0;
let mut match_history = Vec::<u16>::with_capacity(s.len());
let mut i = 0;

while let Some(&c) = s.get(i) {
loop {
if c == part[matched] {
matched += 1;

break;
} else if let Some(&next_matched) = kmp_table.get(matched.wrapping_sub(1)) {
matched = usize::from(next_matched);
} else {
break;
}
}

if matched == part.len() {
match_history.truncate(match_history.len() - (part.len() - 1));
matched = usize::from(match_history.last().copied().unwrap_or_default());
} else {
s[match_history.len()] = c;
match_history.push(matched as _);
}

i += 1;
}

s.truncate(match_history.len());

String::from_utf8(s).ok().unwrap()
}
}

// ------------------------------------------------------ snip ------------------------------------------------------ //

impl super::Solution for Solution {
fn remove_occurrences(s: String, part: String) -> String {
Self::remove_occurrences(s, part)
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::Solution>();
}
}
22 changes: 22 additions & 0 deletions src/problem_1910_remove_all_occurrences_of_a_substring/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pub mod kmp;

pub trait Solution {
fn remove_occurrences(s: String, part: String) -> String;
}

#[cfg(test)]
mod tests {
use super::Solution;

pub fn run<S: Solution>() {
let test_cases = [
(("daabcbaabcbc", "abc"), "dab"),
(("axxxxyyyyb", "xy"), "ab"),
(("gjzgbpggjzgbpgsvpwdk", "gjzgbpg"), "svpwdk"),
];

for ((s, part), expected) in test_cases {
assert_eq!(S::remove_occurrences(s.to_string(), part.to_string()), expected);
}
}
}

0 comments on commit 330a572

Please sign in to comment.