diff --git a/src/lib.rs b/src/lib.rs index c581305f..a331bcd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1557,6 +1557,7 @@ pub mod problem_2149_rearrange_array_elements_by_sign; pub mod problem_2150_find_all_lonely_numbers_in_the_array; pub mod problem_2154_keep_multiplying_found_values_by_two; pub mod problem_2155_all_divisions_with_the_highest_score_of_a_binary_array; +pub mod problem_2156_find_substring_with_given_hash_value; pub mod problem_2160_minimum_sum_of_four_digit_number_after_splitting_digits; pub mod problem_2161_partition_array_according_to_given_pivot; pub mod problem_2164_sort_even_and_odd_indices_independently; diff --git a/src/problem_2156_find_substring_with_given_hash_value/iterative.rs b/src/problem_2156_find_substring_with_given_hash_value/iterative.rs new file mode 100644 index 00000000..6e0125b0 --- /dev/null +++ b/src/problem_2156_find_substring_with_given_hash_value/iterative.rs @@ -0,0 +1,80 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +use std::num::NonZeroU64; + +impl Solution { + fn pow_mod(mut base: u64, mut exponent: u32, modulus: NonZeroU64) -> u64 { + let mut result = 1; + + while exponent != 0 { + if exponent & 1 != 0 { + result = (result * base) % modulus; + } + + base = (base * base) % modulus; + exponent >>= 1; + } + + result + } + + pub fn sub_str_hash(s: String, power: i32, modulo: i32, k: i32, hash_value: i32) -> String { + let slice = s.as_bytes(); + let power = u64::from(power as u32); + let modulo = NonZeroU64::new(u64::from(modulo as u32)).unwrap(); + let k = k as u32 as usize; + let hash_value = hash_value as u32; + let n = slice.len(); + let mut current_hash = 0; + + for &c in slice[n - k..].iter().rev() { + current_hash = (current_hash * power + u64::from(c - (b'a' - 1))) % modulo; + } + + let mut iter = slice.iter().zip(&slice[k..]); + let mut i = n - k; + let mut start = 0; + let base = Self::pow_mod(power, k as u32 - 1, modulo); + + loop { + if current_hash as u32 == hash_value { + start = i; + } + + if let Some((&new, &old)) = iter.next_back() { + let (new, old) = (new - (b'a' - 1), old - (b'a' - 1)); + let old_hash = (base * u64::from(old)) % modulo; + + current_hash = ((current_hash + modulo.get() - old_hash) * power + u64::from(new)) % modulo; + i -= 1; + } else { + break; + } + } + + let mut result = s; + + result.truncate(start + k); + result.replace_range(..start, ""); + + result + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn sub_str_hash(s: String, power: i32, modulo: i32, k: i32, hash_value: i32) -> String { + Self::sub_str_hash(s, power, modulo, k, hash_value) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_2156_find_substring_with_given_hash_value/mod.rs b/src/problem_2156_find_substring_with_given_hash_value/mod.rs new file mode 100644 index 00000000..ed8d54d2 --- /dev/null +++ b/src/problem_2156_find_substring_with_given_hash_value/mod.rs @@ -0,0 +1,18 @@ +pub mod iterative; + +pub trait Solution { + fn sub_str_hash(s: String, power: i32, modulo: i32, k: i32, hash_value: i32) -> String; +} + +#[cfg(test)] +mod tests { + use super::Solution; + + pub fn run() { + let test_cases = [(("leetcode", 7, 20, 2, 0), "ee"), (("fbxzaad", 31, 100, 3, 32), "fbx")]; + + for ((s, power, modulo, k, hash_value), expected) in test_cases { + assert_eq!(S::sub_str_hash(s.to_string(), power, modulo, k, hash_value), expected); + } + } +}