Skip to content

Commit

Permalink
Add problem 1912: Design Movie Rental System
Browse files Browse the repository at this point in the history
  • Loading branch information
EFanZh committed Aug 31, 2024
1 parent ccb7655 commit 84887f4
Show file tree
Hide file tree
Showing 4 changed files with 311 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 @@ -1426,6 +1426,7 @@ pub mod problem_1906_minimum_absolute_difference_queries;
pub mod problem_1909_remove_one_element_to_make_the_array_strictly_increasing;
pub mod problem_1910_remove_all_occurrences_of_a_substring;
pub mod problem_1911_maximum_alternating_subsequence_sum;
pub mod problem_1912_design_movie_rental_system;
pub mod problem_1913_maximum_product_difference_between_two_pairs;
pub mod problem_1914_cyclically_rotating_a_grid;
pub mod problem_1915_number_of_wonderful_substrings;
Expand Down
113 changes: 113 additions & 0 deletions src/problem_1912_design_movie_rental_system/btree_set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// ------------------------------------------------------ snip ------------------------------------------------------ //

use std::collections::hash_map::Entry;
use std::collections::{BTreeSet, HashMap};

struct MovieState {
unrented: BTreeSet<(u32, u32)>,
prices: HashMap<u32, u32>,
}

pub struct MovieRentingSystem {
unrented: HashMap<u32, MovieState>,
rented: BTreeSet<(u32, u32, u32)>,
}

impl MovieRentingSystem {
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
let _ = n;
let mut unrented = HashMap::<u32, MovieState>::new();

for entry in entries {
let [shop, movie, price] = <[_; 3]>::map(entry.try_into().ok().unwrap(), |x| x as u32);

match unrented.entry(movie) {
Entry::Occupied(entry) => {
let state = entry.into_mut();

state.unrented.insert((price, shop));
state.prices.insert(shop, price);
}
Entry::Vacant(entry) => {
entry.insert(MovieState {
unrented: BTreeSet::from([(price, shop)]),
prices: HashMap::from([(shop, price)]),
});
}
}
}

Self {
unrented,
rented: BTreeSet::new(),
}
}

fn search(&self, movie: i32) -> Vec<i32> {
let mut result = Vec::new();

if let Some(state) = self.unrented.get(&(movie as _)) {
result.extend(state.unrented.iter().take(5).map(|&(_, shop)| shop as i32));
}

result
}

fn rent(&mut self, shop: i32, movie: i32) {
let (shop, movie) = (shop as u32, movie as u32);
let state = self.unrented.get_mut(&movie).unwrap();
let price = state.prices[&shop];

state.unrented.remove(&(price, shop));
self.rented.insert((price, shop, movie));
}

fn drop(&mut self, shop: i32, movie: i32) {
let (shop, movie) = (shop as u32, movie as u32);
let state = self.unrented.get_mut(&movie).unwrap();
let price = state.prices[&shop];

state.unrented.insert((price, shop));
self.rented.remove(&(price, shop, movie));
}

fn report(&self) -> Vec<Vec<i32>> {
self.rented
.iter()
.take(5)
.map(|&(_, shop, movie)| vec![shop as _, movie as _])
.collect()
}
}

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

impl super::MovieRentingSystem for MovieRentingSystem {
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
Self::new(n, entries)
}

fn search(&self, movie: i32) -> Vec<i32> {
self.search(movie)
}

fn rent(&mut self, shop: i32, movie: i32) {
self.rent(shop, movie);
}

fn drop(&mut self, shop: i32, movie: i32) {
self.drop(shop, movie);
}

fn report(&self) -> Vec<Vec<i32>> {
self.report()
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::MovieRentingSystem>();
}
}
107 changes: 107 additions & 0 deletions src/problem_1912_design_movie_rental_system/btree_set_2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// ------------------------------------------------------ snip ------------------------------------------------------ //

use std::collections::hash_map::Entry;
use std::collections::{BTreeSet, HashMap};

pub struct MovieRentingSystem {
prices: HashMap<(u32, u32), u32>,
unrented: HashMap<u32, BTreeSet<(u32, u32)>>,
rented: BTreeSet<(u32, u32, u32)>,
}

impl MovieRentingSystem {
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
let _ = n;
let mut unrented = HashMap::<u32, BTreeSet<(u32, u32)>>::new();
let mut prices = HashMap::<(u32, u32), u32>::new();

for entry in entries {
let [shop, movie, price] = <[_; 3]>::map(entry.try_into().ok().unwrap(), |x| x as u32);

match unrented.entry(movie) {
Entry::Occupied(entry) => {
entry.into_mut().insert((price, shop));
}
Entry::Vacant(entry) => {
entry.insert(BTreeSet::from([(price, shop)]));
}
}

prices.insert((movie, shop), price);
}

Self {
unrented,
prices,
rented: BTreeSet::new(),
}
}

fn search(&self, movie: i32) -> Vec<i32> {
let mut result = Vec::new();

if let Some(state) = self.unrented.get(&(movie as _)) {
result.extend(state.iter().take(5).map(|&(_, shop)| shop as i32));
}

result
}

fn rent(&mut self, shop: i32, movie: i32) {
let (shop, movie) = (shop as u32, movie as u32);
let state = self.unrented.get_mut(&movie).unwrap();
let price = self.prices[&(movie, shop)];

state.remove(&(price, shop));
self.rented.insert((price, shop, movie));
}

fn drop(&mut self, shop: i32, movie: i32) {
let (shop, movie) = (shop as u32, movie as u32);
let state = self.unrented.get_mut(&movie).unwrap();
let price = self.prices[&(movie, shop)];

state.insert((price, shop));
self.rented.remove(&(price, shop, movie));
}

fn report(&self) -> Vec<Vec<i32>> {
self.rented
.iter()
.take(5)
.map(|&(_, shop, movie)| vec![shop as _, movie as _])
.collect()
}
}

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

impl super::MovieRentingSystem for MovieRentingSystem {
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self {
Self::new(n, entries)
}

fn search(&self, movie: i32) -> Vec<i32> {
self.search(movie)
}

fn rent(&mut self, shop: i32, movie: i32) {
self.rent(shop, movie);
}

fn drop(&mut self, shop: i32, movie: i32) {
self.drop(shop, movie);
}

fn report(&self) -> Vec<Vec<i32>> {
self.report()
}
}

#[cfg(test)]
mod tests {
#[test]
fn test_solution() {
super::super::tests::run::<super::MovieRentingSystem>();
}
}
90 changes: 90 additions & 0 deletions src/problem_1912_design_movie_rental_system/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
pub mod btree_set;
pub mod btree_set_2;

pub trait MovieRentingSystem {
fn new(n: i32, entries: Vec<Vec<i32>>) -> Self;
fn search(&self, movie: i32) -> Vec<i32>;
fn rent(&mut self, shop: i32, movie: i32);
fn drop(&mut self, shop: i32, movie: i32);
fn report(&self) -> Vec<Vec<i32>>;
}

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

enum Operation {
Search(i32, &'static [i32]),
Rent(i32, i32),
Drop(i32, i32),
Report(&'static [[i32; 2]]),
}

pub fn run<M: MovieRentingSystem>() {
let test_cases = [
(
(
3,
&[[0, 1, 5], [0, 2, 6], [0, 3, 7], [1, 1, 4], [1, 2, 7], [2, 1, 5]] as &[_],
),
&[
Operation::Search(1, &[1, 0, 2]),
Operation::Rent(0, 1),
Operation::Rent(1, 2),
Operation::Report(&[[0, 1], [1, 2]]),
Operation::Drop(1, 2),
Operation::Search(2, &[0, 1]),
] as &[_],
),
(
(
10,
&[
[0, 418, 3],
[9, 5144, 46],
[2, 8986, 29],
[6, 1446, 28],
[3, 8215, 97],
[7, 9105, 34],
[6, 9105, 30],
[5, 1722, 94],
[9, 528, 40],
[3, 850, 77],
[3, 7069, 40],
[8, 1997, 42],
[0, 8215, 28],
[7, 4050, 80],
[4, 7100, 97],
[4, 9686, 32],
[4, 2566, 93],
[2, 8320, 12],
[2, 5495, 56],
],
),
&[
Operation::Search(7837, &[]),
Operation::Search(5495, &[2]),
Operation::Rent(4, 7100),
Operation::Search(9105, &[6, 7]),
Operation::Search(1446, &[6]),
Operation::Report(&[[4, 7100]]),
Operation::Search(9869, &[]),
Operation::Drop(4, 7100),
],
),
];

for ((n, entries), operations) in test_cases {
let mut movie_renting_system = M::new(n, entries.iter().map(Vec::from).collect());

for operation in operations {
match *operation {
Operation::Search(movie, expected) => assert_eq!(movie_renting_system.search(movie), expected),
Operation::Rent(shop, movie) => movie_renting_system.rent(shop, movie),
Operation::Drop(shop, movie) => movie_renting_system.drop(shop, movie),
Operation::Report(expected) => assert_eq!(movie_renting_system.report(), expected),
}
}
}
}
}

0 comments on commit 84887f4

Please sign in to comment.