2353. Design a Food Rating System

  • μŒμ‹μ  λ³„λ‘œ μ μˆ˜μ— λ”°λ₯Έ heap을 λ§Œλ“€κ³  μŒμ‹μ˜ 점수λ₯Ό μˆ˜μ • ν•˜λ©΄μ„œ μ΅œκ³ μ μ„ κ°€μ§„ μŒμ‹μ„ μ°Ύμ•„λ‚΄λŠ” 문제.
  • make_heap의 μ‚¬μš©λ²•μ΄ μ’€ ν—·κ°ˆλ Έμ—ˆλ˜ 것 κ°™λ‹€.
    • make_heap은 μ£Όμ–΄μ§„ comparatorλ₯Ό κΈ°μ€€μœΌλ‘œ max heap을 λ§Œλ“ λ‹€.
      • λ”°λΌμ„œ μ μˆ˜λŠ” μ˜€λ¦„μ°¨μˆœ, 이름은 λ‚΄λ¦Όμ°¨μˆœμœΌλ‘œ 계단식 μ •λ ¬ν•˜λŠ” comparatorλ₯Ό λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.
    • max heap의 μ΅œλŒ€ 값을 κ°€μ§„ μš”μ†ŒλŠ” vector의 첫번째 μš”μ†Œκ°€ λœλ‹€.
    • μ‹œκ°„ λ³΅μž‘λ„λŠ” 이 λœλ‹€.
  • μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜λŠ” λ°©μ‹μœΌλ‘œ ν’€μ–΄μ•Ό 제 μ‹œκ°„ μ•ˆμ— 싀행될 수 μžˆλ‹€.
    • κΈ°μ‘΄ 객체λ₯Ό μˆ˜μ •ν•˜λ €λ©΄ 맀번 heap을 λ‹€μ‹œ μ •λ ¬ν•΄μ•Ό ν•˜λŠ”λ° μž‘μ—…μ˜ μˆ˜κ°€ μš”μ†Œμ˜ 수 와 λΉ„μŠ·ν•˜λ‹€κ³  κ°€μ •ν•˜λ©΄ μ‹œκ°„ λ³΅μž‘λ„λŠ” κ°€ λœλ‹€.
    • κ·Έλ³΄λ‹€λŠ” κΈ°μ‘΄ 객체λ₯Ό μ°Ύμ•„μ„œ λ§ˆν‚Ή invalidate = trueν•˜κ³  μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•˜λŠ” 편이 λ‚«λ‹€.
    • μƒˆλ‘œμš΄ 객체λ₯Ό μƒμ„±ν•΄μ„œ 넣을 경우 μ‹œκ°„ λ³΅μž‘λ„λŠ” 이 λœλ‹€.
    • μˆ˜μ •λ  μ μˆ˜μ™€ κΈ°μ‘΄ μ μˆ˜κ°€ 같은 경우 μž‘μ—…μ„ κ±΄λ„ˆλ›°λŠ” 것도 μ„±λŠ₯에 μ–΄λŠμ •λ„ (μ‹€ν–‰ μ‹œκ°„ λ°±λΆ„μœ„ 34% β†’ 58%) 영ν–₯이 μžˆλ‹€.
  • 졜고 점수λ₯Ό κ°€μ§„ μŒμ‹μ„ 찾을 λ•Œ λ§ˆν‚Ήλœ μŒμ‹μ„ μ œκ±°ν•œλ‹€.
    • heap의 μ΅œκ³ μ μ„ κ°€μ§„ μš”μ†Œκ°€ λ§ˆν‚Ήλœ μŒμ‹μΈ 경우 pop_heap을 ν†΅ν•΄μ„œ μ œκ±°ν•œλ‹€.
  • 이름 - μŒμ‹, μŒμ‹μ  이름 - μŒμ‹ λͺ©λ‘μ˜ map을 생성할 λ•Œ key의 정렬이 ν•„μš” μ—†μœΌλ―€λ‘œ unordered_map을 μ‚¬μš©ν•˜λ©΄ μœ μ˜λ―Έν•œ μ„±λŠ₯ ν–₯상을 μ΄λŒμ–΄λ‚Ό 수 μžˆλ‹€ (μ‹€ν–‰ μ‹œκ°„ λ°±λΆ„μœ„ 58% β†’ 97%).
class FoodRatings { public: FoodRatings(vector<string>& foods, vector<string>& cuisines, vector<int>& ratings) { // make all foods for (int i = 0; i < foods.size(); ++i) { auto food = make_shared<Food>( Food{cuisines[i], foods[i], ratings[i]}); all_foods[food->name] = food; all_cuisines[food->cuisine].push_back(food); } // make heaps for each cuisines for (auto& entry : all_cuisines) { make_heap(entry.second.begin(), entry.second.end(), compare); } } void changeRating(string food, int newRating) { // find food & check ratings auto& ptr = all_foods[food]; if (ptr->rating == newRating) return; // invalidate previous food ptr->invalid = true; // create new food auto new_ptr = make_shared<Food>( Food{ptr->cuisine, ptr->name, newRating}); // add new food auto& foods = all_cuisines[ptr->cuisine]; foods.push_back(new_ptr); push_heap(foods.begin(), foods.end(), compare); all_foods[food] = new_ptr; } string highestRated(string cuisine) { auto& foods = all_cuisines[cuisine]; // remove invalid foods from top of the heap while (foods[0]->invalid) { pop_heap(foods.begin(), foods.end(), compare); foods.pop_back(); } return foods[0]->name; } private: struct Food { string cuisine; string name; int rating; bool invalid = false; }; using FoodPtr = shared_ptr<Food>; static bool compare(FoodPtr& lhs, FoodPtr& rhs) { return (lhs->rating != rhs->rating) ? lhs->rating < rhs->rating : lhs->name > rhs->name; } unordered_map<string, FoodPtr> all_foods; unordered_map<string, vector<FoodPtr>> all_cuisines; };