Design a food rating system that can do the following:
- Modify the rating of a food item listed in the system.
- Return the highest-rated food item for a type of cuisine in the system.
Implement the FoodRatings
class:
FoodRatings(String[] foods, String[] cuisines, int[] ratings)
Initializes the system. The food items are described byfoods
,cuisines
andratings
, all of which have a length ofn
.foods[i]
is the name of theith
food,cuisines[i]
is the type of cuisine of theith
food, andratings[i]
is the initial rating of theith
food.
void changeRating(String food, int newRating)
Changes the rating of the food item with the namefood
.String highestRated(String cuisine)
Returns the name of the food item that has the highest rating for the given type ofcuisine
. If there is a tie, return the item with the lexicographically smaller name.
Note that a string x
is lexicographically smaller than string y
if x
comes before y
in dictionary order, that is, either x
is a prefix of y
, or if i
is the first position such that x[i] != y[i]
, then x[i]
comes before y[i]
in alphabetic order.
Design a Food Rating System LeetCode Contest
Example 1:
Input ["FoodRatings", "highestRated", "highestRated", "changeRating", "highestRated", "changeRating", "highestRated"] [[["kimchi", "miso", "sushi", "moussaka", "ramen", "bulgogi"], ["korean", "japanese", "japanese", "greek", "japanese", "korean"], [9, 12, 8, 15, 14, 7]], ["korean"], ["japanese"], ["sushi", 16], ["japanese"], ["ramen", 16], ["japanese"]] Output [null, "kimchi", "ramen", null, "sushi", null, "ramen"]
Explanation FoodRatings foodRatings = new FoodRatings([“kimchi”, “miso”, “sushi”, “moussaka”, “ramen”, “bulgogi”], [“korean”, “japanese”, “japanese”, “greek”, “japanese”, “korean”], [9, 12, 8, 15, 14, 7]); foodRatings.highestRated(“korean”); // return “kimchi” // “kimchi” is the highest rated korean food with a rating of 9. foodRatings.highestRated(“japanese”); // return “ramen” // “ramen” is the highest rated japanese food with a rating of 14. foodRatings.changeRating(“sushi”, 16); // “sushi” now has a rating of 16. foodRatings.highestRated(“japanese”); // return “sushi” // “sushi” is the highest rated japanese food with a rating of 16. foodRatings.changeRating(“ramen”, 16); // “ramen” now has a rating of 16. foodRatings.highestRated(“japanese”); // return “ramen” // Both “sushi” and “ramen” have a rating of 16. // However, “ramen” is lexicographically smaller than “sushi”.
Constraints:
1 <= n <= 2 * 104
n == foods.length == cuisines.length == ratings.length
1 <= foods[i].length, cuisines[i].length <= 10
foods[i]
,cuisines[i]
consist of lowercase English letters.1 <= ratings[i] <= 108
- All the strings in
foods
are distinct. food
will be the name of a food item in the system across all calls tochangeRating
.cuisine
will be a type of cuisine of at least one food item in the system across all calls tohighestRated
.- At most
2 * 104
calls in total will be made tochangeRating
andhighestRated
.
Solution
class FoodRatings {
public:
unordered_map<string, map<int, set<string>>> cuisine2rateAndFood;
unordered_map<string, pair<int, string>> food2cuisineAndRate;
FoodRatings(vector<string>& foods, vector<string>& cuisines, vector<int>& ratings) {
int n = foods.size();
for (int i = 0; i < n; ++i) {
cuisine2rateAndFood[cuisines[i]][ratings[i]].insert(foods[i]);
food2cuisineAndRate[foods[i]] = make_pair(ratings[i], cuisines[i]);
}
}
void changeRating(string food, int newRating) {
auto [prevRating, cuisine] = food2cuisineAndRate[food];
cuisine2rateAndFood[cuisine][prevRating].erase(food);
if (cuisine2rateAndFood[cuisine][prevRating].empty()) {
cuisine2rateAndFood[cuisine].erase(prevRating);
}
cuisine2rateAndFood[cuisine][newRating].insert(food);
food2cuisineAndRate[food].first = newRating;
}
string highestRated(string cuisine) {
auto foodSet = cuisine2rateAndFood[cuisine].rbegin()->second;
return *foodSet.begin();
}
};
/**
* Your FoodRatings object will be instantiated and called as such:
* FoodRatings* obj = new FoodRatings(foods, cuisines, ratings);
* obj->changeRating(food,newRating);
* string param_2 = obj->highestRated(cuisine);
*/
from sortedcontainers import SortedSet
class FoodRatings:
def __init__(self, foods: List[str], cuisine: List[str], ratings: List[int]):
self.cuisines = defaultdict(lambda: SortedSet(key=lambda x: (-x[0], x[1])))
self.food_to_cuisine = dict()
self.food_to_rating = dict()
for index in range(len(foods)):
_cuisine, food, rating = cu[index], foods[index], ratings[index]
self.cuisines[_cuisine].add((rating, food))
self.food_to_cuisine[food] = _cuisine
self.food_to_rating[food] = rating
def changeRating(self, food: str, new_rating: int) -> None:
old_rating = self.food_to_rating[food]
cuisine = self.food_to_cuisine[food]
self.cuisines[cuisine].discard((old_rating, food))
self.cuisines[cuisine].add((new_rating, food))
self.food_to_rating[food] = new_rating
def highestRated(self, cuisine: str) -> str:
return self.cuisines[cuisine][0][1]
class FoodRatings {
Map<String, TreeSet> cuisineMap;
Map<String, Food> foodMap;
TreeSet foodSet;
public FoodRatings(String[] foods, String[] cuisines, int[] ratings) {
foodMap = new HashMap<>();
cuisineMap = new HashMap<>();
for (int i = 0; i < foods.length; ++i) {
Food food = new Food(foods[i], cuisines[i], ratings[i]);
foodMap.put(food.name, food);
if (!cuisineMap.containsKey(food.cuisine)) {
cuisineMap.put(food.cuisine, new TreeSet<>((a, b) -> a.rating == b.rating ?
a.name.compareTo(b.name) : b.rating - a.rating));
}
cuisineMap.get(food.cuisine).add(food);
}
}
public void changeRating(String food, int newRating) {
Food f = foodMap.get(food);
foodSet = cuisineMap.get(f.cuisine);
foodSet.remove(f);
f.rating = newRating;
foodSet.add(f);
}
public String highestRated(String cuisine) {
foodSet = cuisineMap.get(cuisine);
return foodSet.first().name;
}
}
class Food {
String name;
String cuisine;
int rating;
Food(String name, String cuisine, int rating) {
this.name = name;
this.rating = rating;
this.cuisine = cuisine;
}
}
Happy Learning – If you require any further information, feel free to contact me.