diff --git a/src/lib.rs b/src/lib.rs index 506a75b2..fb8c9da4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1575,6 +1575,7 @@ pub mod problem_2177_find_three_consecutive_integers_that_sum_to_a_given_number; pub mod problem_2178_maximum_split_of_positive_even_integers; pub mod problem_2180_count_integers_with_even_digit_sum; pub mod problem_2181_merge_nodes_in_between_zeros; +pub mod problem_2182_construct_string_with_repeat_limit; pub mod problem_2183_count_array_pairs_divisible_by_k; pub mod problem_2185_counting_words_with_a_given_prefix; pub mod problem_2186_minimum_number_of_steps_to_make_two_strings_anagram_ii; diff --git a/src/problem_2182_construct_string_with_repeat_limit/greedy.rs b/src/problem_2182_construct_string_with_repeat_limit/greedy.rs new file mode 100644 index 00000000..d185bc28 --- /dev/null +++ b/src/problem_2182_construct_string_with_repeat_limit/greedy.rs @@ -0,0 +1,82 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +use std::iter; +use std::num::NonZeroU32; + +impl Solution { + pub fn repeat_limited_string(s: String, repeat_limit: i32) -> String { + let mut s = s.into_bytes(); + let repeat_limit = NonZeroU32::new(repeat_limit as _).unwrap(); + let mut counts = [0_u32; 26]; + + for &c in &s { + counts[usize::from(c) - usize::from(b'a')] += 1; + } + + s.clear(); + + let mut i = 25; + + 'outer: while let Some(count) = counts.get(i).copied() { + if count == 0 { + i = i.wrapping_sub(1); + + continue; + } + + let mut cycles = count / repeat_limit; + let mut extra = count % repeat_limit; + + if extra == 0 { + cycles -= 1; + extra = repeat_limit.get(); + } + + let mut j = i.wrapping_sub(1); + + for _ in 0..cycles { + s.extend(iter::repeat(b'a' + i as u8).take(repeat_limit.get() as _)); + + loop { + if let Some(count_2) = counts.get_mut(j) { + if *count_2 == 0 { + j = j.wrapping_sub(1); + } else { + *count_2 -= 1; + + break; + } + } else { + break 'outer; + } + } + + s.push(b'a' + j as u8); + } + + s.extend(iter::repeat(b'a' + i as u8).take(extra as _)); + + i = j; + } + + String::from_utf8(s).ok().unwrap() + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn repeat_limited_string(s: String, repeat_limit: i32) -> String { + Self::repeat_limited_string(s, repeat_limit) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_2182_construct_string_with_repeat_limit/greedy_2.rs b/src/problem_2182_construct_string_with_repeat_limit/greedy_2.rs new file mode 100644 index 00000000..5531a501 --- /dev/null +++ b/src/problem_2182_construct_string_with_repeat_limit/greedy_2.rs @@ -0,0 +1,72 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +use std::num::NonZeroU32; + +impl Solution { + pub fn repeat_limited_string(s: String, repeat_limit: i32) -> String { + let mut s = s.into_bytes(); + let repeat_limit = NonZeroU32::new(repeat_limit as _).unwrap(); + let mut counts = [0_u32; 26]; + + for &c in &s { + counts[usize::from(c) - usize::from(b'a')] += 1; + } + + s.clear(); + + let mut i = 25; + + 'outer: while let Some(mut count) = counts.get(i).copied() { + let mut j = i.wrapping_sub(1); + let mut budget = repeat_limit.get(); + + while count != 0 { + if budget == 0 { + loop { + if let Some(count_2) = counts.get_mut(j) { + if *count_2 == 0 { + j = j.wrapping_sub(1); + } else { + *count_2 -= 1; + + break; + } + } else { + break 'outer; + } + } + + s.push(b'a' + j as u8); + budget = repeat_limit.get(); + } + + s.push(b'a' + i as u8); + budget -= 1; + + count -= 1; + } + + i = j; + } + + String::from_utf8(s).ok().unwrap() + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn repeat_limited_string(s: String, repeat_limit: i32) -> String { + Self::repeat_limited_string(s, repeat_limit) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_2182_construct_string_with_repeat_limit/mod.rs b/src/problem_2182_construct_string_with_repeat_limit/mod.rs new file mode 100644 index 00000000..c96e9599 --- /dev/null +++ b/src/problem_2182_construct_string_with_repeat_limit/mod.rs @@ -0,0 +1,30 @@ +pub mod greedy; +pub mod greedy_2; + +pub trait Solution { + fn repeat_limited_string(s: String, repeat_limit: i32) -> String; +} + +#[cfg(test)] +mod tests { + use super::Solution; + + pub fn run() { + let test_cases = [ + (("cczazcc", 3), "zzcccac"), + (("aababab", 2), "bbabaa"), + ( + ("robnsdvpuxbapuqgopqvxdrchivlifeepy", 2), + "yxxvvuvusrrqqppopponliihgfeeddcbba", + ), + ( + ("xyutfpopdynbadwtvmxiemmusevduloxwvpkjioizvanetecnuqbqqdtrwrkgt", 1), + "zyxyxwxwvwvuvuvututstrtrtqpqpqponononmlmkmkjigifiededededcbaba", + ), + ]; + + for ((s, repeat_limit), expected) in test_cases { + assert_eq!(S::repeat_limited_string(s.to_string(), repeat_limit), expected); + } + } +}