leetcode/src/problem/p2353_design_a_food_rating_system.rs
2025-02-28 11:53:38 +08:00

138 lines
3.6 KiB
Rust

/**
* [2353] Design a Food Rating System
*/
pub struct Solution {}
// submission codes start here
use std::cmp::Ordering;
use std::collections::{BinaryHeap, HashMap};
#[derive(Debug, Clone, Eq, PartialEq)]
struct Food {
name: String,
cuisine: String,
rating: i32,
}
impl Food {
fn new(name: String, cuisine: String, rating: i32) -> Self {
Self {
name,
cuisine,
rating,
}
}
fn update_rating(&self, new_rating: i32) -> Self {
Self {
name: self.name.clone(),
cuisine: self.cuisine.clone(),
rating: new_rating,
}
}
}
impl Ord for Food {
fn cmp(&self, other: &Self) -> Ordering {
match self.rating.cmp(&other.rating) {
Ordering::Equal => other.name.cmp(&self.name),
a => a,
}
}
}
impl PartialOrd for Food {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
struct FoodRatings {
food_map: HashMap<String, Food>,
cuisine_heap: HashMap<String, BinaryHeap<Food>>,
}
/**
* `&self` means the method takes an immutable reference.
* If you need a mutable reference, change it to `&mut self` instead.
*/
impl FoodRatings {
fn new(foods: Vec<String>, cuisines: Vec<String>, ratings: Vec<i32>) -> Self {
let mut food_map = HashMap::new();
let mut cuisine_heap = HashMap::new();
for ((name, cuisine), &rating) in foods.iter().zip(cuisines.iter()).zip(ratings.iter()) {
food_map.insert(
name.clone(),
Food::new(name.clone(), cuisine.clone(), rating),
);
let heap = cuisine_heap
.entry(cuisine.clone())
.or_insert(BinaryHeap::new());
heap.push(Food::new(name.clone(), cuisine.clone(), rating.clone()));
}
Self {
food_map,
cuisine_heap,
}
}
fn change_rating(&mut self, food: String, new_rating: i32) {
let food_entry = self.food_map.get_mut(&food).unwrap();
food_entry.rating = new_rating;
let heap = self.cuisine_heap.get_mut(&food_entry.cuisine).unwrap();
heap.push(food_entry.update_rating(new_rating));
}
fn highest_rated(&mut self, cuisine: String) -> String {
let heap = self.cuisine_heap.get_mut(&cuisine).unwrap();
while let Some(head) = heap.peek() {
let food_entry = self.food_map.get(&head.name).unwrap();
if head.rating == food_entry.rating {
return food_entry.name.clone();
}
heap.pop();
}
"".to_owned()
}
}
/**
* Your FoodRatings object will be instantiated and called as such:
* let obj = FoodRatings::new(foods, cuisines, ratings);
* obj.change_rating(food, newRating);
* let ret_2: String = obj.highest_rated(cuisine);
*/
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_2353() {
let mut ratings = FoodRatings::new(
vec_string!("kimchi", "miso", "sushi", "moussaka", "ramen", "bulgogi"),
vec_string!("korean", "japanese", "japanese", "greek", "japanese", "korean"),
vec![9, 12, 8, 15, 14, 7],
);
assert_eq!("kimchi", ratings.highest_rated("korean".to_owned()));
assert_eq!("ramen", ratings.highest_rated("japanese".to_owned()));
ratings.change_rating("sushi".to_owned(), 16);
assert_eq!("sushi", ratings.highest_rated("japanese".to_owned()));
ratings.change_rating("ramen".to_owned(), 16);
assert_eq!("ramen", ratings.highest_rated("japanese".to_owned()));
}
}