Skip to content

Commit

Permalink
Add problem 2209: Minimum White Tiles After Covering With Carpets
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Oct 13, 2024
1 parent f1faf8d commit 550dbcc
Show file tree
Hide file tree
Showing 3 changed files with 157 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 @@ -1648,6 +1648,7 @@ pub mod problem_2203_minimum_weighted_subgraph_with_the_required_paths;
pub mod problem_2206_divide_array_into_equal_pairs;
pub mod problem_2207_maximize_number_of_subsequences_in_a_string;
pub mod problem_2208_minimum_operations_to_halve_array_sum;
pub mod problem_2209_minimum_white_tiles_after_covering_with_carpets;
pub mod problem_2210_count_hills_and_valleys_in_an_array;
pub mod problem_2215_find_the_difference_of_two_arrays;
pub mod problem_2216_minimum_deletions_to_make_array_beautiful;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
pub struct Solution;

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

use std::num::NonZeroU16;

impl Solution {
fn helper(floor: &mut [bool], mut num_carpets: u16, carpet_len: NonZeroU16) -> u16 {
const CACHE_CAPACITY: usize = 1 << 10;
const CACHE_MASK: usize = CACHE_CAPACITY - 1;

let Some(first_white) = floor.iter().position(|&is_white| is_white) else {
return 0;
};

let Some(last_white) = floor[first_white + 1..].iter().rposition(|&is_white| is_white) else {
return 0;
};

let floor = &mut floor[first_white..first_white + last_white + 2];

let count_white = |s: &[bool]| s.iter().fold(0, |count, &is_white| count + u16::from(is_white));

let Some(total_carpet_length) = carpet_len.get().checked_mul(num_carpets) else {
return 0;
};

if total_carpet_length > floor.len() as _ {
return 0;
}

if carpet_len.get() == 1 {
return count_white(floor).saturating_sub(total_carpet_length);
}

let mut retained = 0;
let mut prev_is_white = false;
let mut length = 0;
let mut i = 0;

while let Some(&is_white) = floor.get(i) {
if is_white == prev_is_white {
length += 1;

if prev_is_white && length as u16 == carpet_len.get() {
num_carpets -= 1;

if num_carpets == 0 {
return count_white(&floor[..retained]) + count_white(&floor[i + 1..]);
}

length = 0;
}
} else {
floor.copy_within(i - length..i, retained);
retained += length;
prev_is_white = is_white;
length = 1;
}

i += 1;
}

floor.copy_within(i - length.., retained);
retained += length;

let floor = &floor[..retained];
let white_count = count_white(&floor[..usize::from(carpet_len.get()) - 1]);

let iter = floor
.iter()
.zip(&floor[usize::from(carpet_len.get()) - 1..])
.enumerate();

let mut cache = [0_u16; CACHE_CAPACITY];
let cache_size = floor.len() - usize::from(carpet_len.get()) + 1;

for _ in 1..=num_carpets {
let mut white_count = white_count;

iter.clone().for_each(|(i, (&old, &new))| {
white_count += u16::from(new);

cache[i & CACHE_MASK] = white_count + cache[(i + usize::from(carpet_len.get())) & CACHE_MASK];

white_count -= u16::from(old);
});

let mut prev_count = 0;

cache.iter_mut().take(cache_size).rev().for_each(|count| {
prev_count = prev_count.max(*count);
*count = prev_count;
});
}

count_white(floor) - cache[0]
}

pub fn minimum_white_tiles(floor: String, num_carpets: i32, carpet_len: i32) -> i32 {
i32::from(Self::helper(
&mut floor.into_bytes().into_iter().map(|c| c != b'0').collect::<Vec<_>>(),
num_carpets as _,
NonZeroU16::new(carpet_len as _).unwrap(),
))
}
}

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

impl super::Solution for Solution {
fn minimum_white_tiles(floor: String, num_carpets: i32, carpet_len: i32) -> i32 {
Self::minimum_white_tiles(floor, num_carpets, carpet_len)
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::Solution>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pub mod dynamic_programming;

pub trait Solution {
fn minimum_white_tiles(floor: String, num_carpets: i32, carpet_len: i32) -> i32;
}

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

pub fn run<S: Solution>() {
let test_cases = [
(("10110101", 2, 2), 2),
(("11111", 2, 3), 0),
(("110000", 1, 1), 1),
(("0111101", 1, 2), 3),
(("1", 1, 1), 0),
(("0000", 1, 1), 0),
(
("1000000000001000000100111100001101111000000001001111110000000000", 6, 4),
3,
),
(("11010111011001011110010001011001001101101010100010100010000100101011001001100100111010100001100101001100001000011110101000000101110000000100101001101011001100101100101000101110101100001011000011101001001000001111010111100111000000100011100000110111000000011010011011110000101100001101011000101011110111100110110110000100011000000010011010101001010011001110001000000111010010011000110100100101010010100111000110111100110100100110100101101100010000101001110010000101000100000101110111100110011110101010011111111001110010110011111101001000111", 197, 346), 0),
];

for ((floor, num_carpets, carpet_len), expected) in test_cases {
assert_eq!(
S::minimum_white_tiles(floor.to_string(), num_carpets, carpet_len),
expected,
);
}
}
}

0 comments on commit 550dbcc

Please sign in to comment.