Skip to content

Commit

Permalink
Add problem 1942: The Number of the Smallest Unoccupied Chair
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed May 20, 2024
1 parent 17f942b commit b3ec5db
Show file tree
Hide file tree
Showing 3 changed files with 202 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 @@ -1436,6 +1436,7 @@ pub mod problem_1935_maximum_number_of_words_you_can_type;
pub mod problem_1936_add_minimum_number_of_rungs;
pub mod problem_1937_maximum_number_of_points_with_cost;
pub mod problem_1941_check_if_all_characters_have_equal_number_of_occurrences;
pub mod problem_1942_the_number_of_the_smallest_unoccupied_chair;
pub mod problem_1944_number_of_visible_people_in_a_queue;
pub mod problem_1945_sum_of_digits_of_string_after_convert;
pub mod problem_1952_three_divisors;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
pub struct Solution;

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

use std::cmp::{Ordering, Reverse};
use std::collections::BinaryHeap;
use std::convert::TryInto;
use std::mem;

struct Item {
leaving: u32,
chair: u32,
}

impl PartialEq for Item {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}

impl Eq for Item {}

impl PartialOrd for Item {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}

impl Ord for Item {
fn cmp(&self, other: &Self) -> Ordering {
other.leaving.cmp(&self.leaving)
}
}

struct Allocator {
occupied: BinaryHeap<Item>,
idle: BinaryHeap<Reverse<u32>>,
prev_idle: u32,
}

impl Allocator {
fn allocate(&mut self, arrival: u32) -> u32 {
while let Some(&Item { leaving, chair }) = self.occupied.peek() {
if leaving <= arrival {
self.occupied.pop();

if chair == self.prev_idle {
self.prev_idle = self.prev_idle.wrapping_sub(1);
} else {
self.idle.push(Reverse(chair));
}
} else {
break;
}
}

if let Some(Reverse(chair)) = self.idle.pop() {
chair
} else {
self.prev_idle = self.prev_idle.wrapping_add(1);

self.prev_idle
}
}
}

impl Default for Allocator {
fn default() -> Self {
Self {
occupied: BinaryHeap::new(),
idle: BinaryHeap::new(),
prev_idle: u32::MAX,
}
}
}

impl Solution {
fn partition<T>(values: &mut [T], mut f: impl FnMut(&T) -> bool) -> usize {
let mut result = 0;
let mut iter = values.iter_mut();

'outer: while let Some(left) = iter.next() {
if !f(left) {
loop {
if let Some(right) = iter.next_back() {
if f(right) {
mem::swap(left, right);

break;
}
} else {
break 'outer;
}
}
}

result += 1;
}

result
}

pub fn smallest_chair(times: Vec<Vec<i32>>, target_friend: i32) -> i32 {
let mut times = times
.into_iter()
.map(|time| {
let [arrival, leaving]: [_; 2] = time.try_into().ok().unwrap();

(arrival as u32, leaving as u32)
})
.collect::<Box<_>>();

let target_friend = target_friend as u32 as usize;
let target_arrival = times[target_friend].0;
let split = Self::partition(&mut times, |&(arrival_time, _)| arrival_time < target_arrival);
let times = &mut times[..split];

times.sort_unstable_by_key(|&(arrival_time, _)| arrival_time);

let mut allocator = Allocator::default();

for &(arrival, leaving) in &*times {
let chair = allocator.allocate(arrival);

allocator.occupied.push(Item { leaving, chair });
}

allocator.allocate(target_arrival) as _
}
}

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

impl super::Solution for Solution {
fn smallest_chair(times: Vec<Vec<i32>>, target_friend: i32) -> i32 {
Self::smallest_chair(times, target_friend)
}
}

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

#[test]
fn test_item_partial_eq() {
assert!(Item { leaving: 2, chair: 3 } == Item { leaving: 2, chair: 5 });
}

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

pub trait Solution {
fn smallest_chair(times: Vec<Vec<i32>>, target_friend: i32) -> i32;
}

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

pub fn run<S: Solution>() {
let test_cases = [
((&[[1, 4], [2, 3], [4, 6]] as &[_], 1), 1),
((&[[3, 10], [1, 5], [2, 6]], 0), 2),
(
(
&[
[33889, 98676],
[80071, 89737],
[44118, 52565],
[52992, 84310],
[78492, 88209],
[21695, 67063],
[84622, 95452],
[98048, 98856],
[98411, 99433],
[55333, 56548],
[65375, 88566],
[55011, 62821],
[48548, 48656],
[87396, 94825],
[55273, 81868],
[75629, 91467],
],
6,
),
2,
),
];

for ((times, target_friend), expected) in test_cases {
assert_eq!(
S::smallest_chair(times.iter().map(Vec::from).collect(), target_friend),
expected,
);
}
}
}

0 comments on commit b3ec5db

Please sign in to comment.