diff --git a/src/lib.rs b/src/lib.rs index 8e4bb129..a23e4518 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1314,6 +1314,7 @@ pub mod problem_1755_closest_subsequence_sum; pub mod problem_1758_minimum_changes_to_make_alternating_binary_string; pub mod problem_1759_count_number_of_homogenous_substrings; pub mod problem_1760_minimum_limit_of_balls_in_a_bag; +pub mod problem_1763_longest_nice_substring; pub mod problem_1765_map_of_highest_peak; pub mod problem_1768_merge_strings_alternately; pub mod problem_1769_minimum_number_of_operations_to_move_all_balls_to_each_box; diff --git a/src/problem_1763_longest_nice_substring/divide_and_conquer.rs b/src/problem_1763_longest_nice_substring/divide_and_conquer.rs new file mode 100644 index 00000000..905f4515 --- /dev/null +++ b/src/problem_1763_longest_nice_substring/divide_and_conquer.rs @@ -0,0 +1,100 @@ +pub struct Solution; + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +struct Context { + s: Vec, + counts: Box<[[(u8, u8); 26]]>, + result: (u8, u8), +} + +impl Solution { + fn helper(context: &mut Context, start: u8, end: u8) { + let mut count = context.counts[usize::from(end) - 1]; + + if let Some(left_count) = context.counts.get(usize::from(start).wrapping_sub(1)) { + for (target, left_value) in count.iter_mut().zip(left_count) { + target.0 -= left_value.0; + target.1 -= left_value.1; + } + } + + if count + .iter() + .any(|&(upper_count, lower_count)| (upper_count == 0) != (lower_count == 0)) + { + let mut prev = start; + + for i in start..end { + let c = context.s[usize::from(i)]; + + if if c.is_ascii_uppercase() { + count[usize::from(c) - usize::from(b'A')].1 + } else { + count[usize::from(c) - usize::from(b'a')].0 + } == 0 + { + if i - prev > context.result.1 - context.result.0 { + Self::helper(context, prev, i); + } + + prev = i + 1; + } + } + + if end - prev > context.result.1 - context.result.0 { + Self::helper(context, prev, end); + } + } else { + context.result = (start, end); + } + } + + pub fn longest_nice_substring(s: String) -> String { + let n = s.len(); + + let mut context = Context { + s: s.into_bytes(), + counts: vec![[(0_u8, 0_u8); 26]; n].into_boxed_slice(), + result: (0, 0), + }; + + let mut count = [(0_u8, 0_u8); 26]; + + for (target, &c) in context.counts.iter_mut().zip(&context.s) { + if c.is_ascii_uppercase() { + count[usize::from(c) - usize::from(b'A')].0 += 1; + } else { + count[usize::from(c) - usize::from(b'a')].1 += 1; + }; + + *target = count; + } + + Self::helper(&mut context, 0, n as _); + + context + .s + .copy_within(usize::from(context.result.0)..usize::from(context.result.1), 0); + + context.s.truncate(usize::from(context.result.1 - context.result.0)); + + String::from_utf8(context.s).unwrap() + } +} + +// ------------------------------------------------------ snip ------------------------------------------------------ // + +impl super::Solution for Solution { + fn longest_nice_substring(s: String) -> String { + Self::longest_nice_substring(s) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_solution() { + super::super::tests::run::(); + } +} diff --git a/src/problem_1763_longest_nice_substring/mod.rs b/src/problem_1763_longest_nice_substring/mod.rs new file mode 100644 index 00000000..8f44c476 --- /dev/null +++ b/src/problem_1763_longest_nice_substring/mod.rs @@ -0,0 +1,18 @@ +pub mod divide_and_conquer; + +pub trait Solution { + fn longest_nice_substring(s: String) -> String; +} + +#[cfg(test)] +mod tests { + use super::Solution; + + pub fn run() { + let test_cases = [("YazaAay", "aAa"), ("Bb", "Bb"), ("c", "")]; + + for (s, expected) in test_cases { + assert_eq!(S::longest_nice_substring(s.to_string()), expected); + } + } +}