2353. Design a Food Rating System - Explanation

Problem Link



1. Brute Force

class FoodRatings:

    def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]):
        self.foodToRating = {} # food -> rating
        self.cuisineToFood = defaultdict(list) # cuisine -> [food]
        for i in range(len(foods)):
            self.foodToRating[foods[i]] = ratings[i]
            self.cuisineToFood[cuisines[i]].append(foods[i])

    def changeRating(self, food: str, newRating: int) -> None:
        self.foodToRating[food] = newRating

    def highestRated(self, cuisine: str) -> str:
        maxR, res = 0, ""
        for food in self.cuisineToFood[cuisine]:
            r = self.foodToRating[food]
            if r > maxR or (r == maxR and food < res):
                res = food
                maxR = r
        return res

Time & Space Complexity

  • Time complexity:
    • O(n)O(n) time for initialization.
    • O(1)O(1) time for each changeRating()changeRating() function call.
    • O(n)O(n) time for each highestRated()highestRated() function call.
  • Space complexity: O(n)O(n)

2. Heap

class FoodRatings:

    def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]):
        self.foodToRating = {}  # food -> rating
        self.foodToCuisine = {}  # food -> cuisine
        self.cuisineToHeap = defaultdict(list)  # cuisine -> max_heap

        for i in range(len(foods)):
            self.foodToRating[foods[i]] = ratings[i]
            self.foodToCuisine[foods[i]] = cuisines[i]
            heappush(self.cuisineToHeap[cuisines[i]], (-ratings[i], foods[i]))

    def changeRating(self, food: str, newRating: int) -> None:
        cuisine = self.foodToCuisine[food]
        self.foodToRating[food] = newRating
        heappush(self.cuisineToHeap[cuisine], (-newRating, food))

    def highestRated(self, cuisine: str) -> str:
        heap = self.cuisineToHeap[cuisine]
        while heap:
            rating, food = heap[0]
            if -rating == self.foodToRating[food]:
                return food
            heappop(heap)

Time & Space Complexity

  • Time complexity:
    • O(nlogn)O(n \log n) time for initialization.
    • O(logn)O(\log n) time for each changeRating()changeRating() function call.
    • O(logn)O(\log n) time for each highestRated()highestRated() function call.
  • Space complexity: O(n)O(n)

3. Sorted Set

class FoodRatings:

    def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]):
        self.foodToRating = {} # food -> rating
        self.foodToCuisine = {} # food -> cuisine
        self.cuisineToSortedSet = defaultdict(SortedSet) # cuisine -> SortedSet[(rating, food)]

        for i in range(len(foods)):
            self.foodToRating[foods[i]] = ratings[i]
            self.foodToCuisine[foods[i]] = cuisines[i]
            self.cuisineToSortedSet[cuisines[i]].add((-ratings[i], foods[i]))

    def changeRating(self, food: str, newRating: int) -> None:
        cuisine = self.foodToCuisine[food]
        oldRating = self.foodToRating[food]

        self.cuisineToSortedSet[cuisine].remove((-oldRating, food))
        self.foodToRating[food] = newRating
        self.cuisineToSortedSet[cuisine].add((-newRating, food))

    def highestRated(self, cuisine: str) -> str:
        return self.cuisineToSortedSet[cuisine][0][1]

Time & Space Complexity

  • Time complexity:
    • O(nlogn)O(n \log n) time for initialization.
    • O(logn)O(\log n) time for each changeRating()changeRating() function call.
    • O(1)O(1) in Python and O(logn)O(\log n) in other languages for each highestRated()highestRated() function call.
  • Space complexity: O(n)O(n)