Skip to main content

Design a Food Rating System - Solution & Explanation

MediumHash TableDesignHeap (Priority Queue)Ordered Set15 min readAsked at: Amazon, Microsoft, Atlassian +1
Practice this problem

Problem Statement

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 by foods, cuisines and ratings, all of which have a length of n.
    • foods[i] is the name of the ith food,
    • cuisines[i] is the type of cuisine of the ith food, and
    • ratings[i] is the initial rating of the ith food.
  • void changeRating(String food, int newRating) Changes the rating of the food item with the name food.
  • String highestRated(String cuisine) Returns the name of the food item that has the highest rating for the given type of cuisine. 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.

 

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 to changeRating.
  • cuisine will be a type of cuisine of at least one food item in the system across all calls to highestRated.
  • At most 2 * 104 calls in total will be made to changeRating and highestRated.

Approach Overview

Problem Overview: Design a data structure that tracks foods, their cuisines, and ratings. The system must support updating a food's rating and returning the highest-rated food for a cuisine, breaking ties using lexicographical order.

Approach 1: Dictionaries / Hash Maps with Ordered Tracking (O(log n) per update, O(1)–O(log n) query)

This approach stores core relationships using hash tables. Maintain a map from food → (cuisine, rating) and another map from cuisine → ordered collection of foods sorted by rating (descending) and name (ascending). When changeRating runs, update the food's rating and reposition it inside the cuisine's ordered structure. Retrieving highestRated simply returns the first element of the ordered set. The key insight is separating identity lookup (fast with hash maps) from ranking (handled by an ordered container). Time complexity is O(log n) for updates due to reordering, and space complexity is O(n) for storing mappings and ordered structures.

Approach 2: Priority Heap per Cuisine with Lazy Updates (O(log n) update, O(log n) query)

A scalable approach uses a priority queue for each cuisine. Maintain a hash map food → (cuisine, rating) and another map cuisine → max heap containing entries like (-rating, foodName). When the rating changes, push the updated pair into the heap instead of removing the old one. During highestRated, repeatedly check the heap top against the current rating stored in the hash map. If it is outdated, pop it (lazy deletion). The first valid entry is the correct answer. Heap ordering naturally handles rating priority and lexicographic tie-breaking. Each push or pop costs O(log n), and space complexity remains O(n) though the heap may temporarily contain stale entries.

Recommended for interviews: Interviewers typically expect the heap-based design. It demonstrates understanding of system design patterns, priority queues, and lazy deletion to avoid expensive removals. The ordered-set approach is conceptually clean and efficient in languages with strong tree-based containers, but the heap + hash map combination is easier to implement in most interview environments.

Approach 1: Using Dictionaries/Hash Maps

This approach involves using dictionaries (or hash maps) to store and manage the relationships between foods, cuisines, and their ratings. We will have multiple dictionaries to efficiently perform update and retrieval operations.

The code initializes a class with dictionaries to map each food to its corresponding cuisine and rating. Another dictionary maps cuisines to lists of foods, sorted by their negative ratings (to simulate max-heap behavior using sorting). When we change a rating, we update the corresponding entry and re-sort the list for that cuisine. For retrieving the highest-rated food, we return the first item in the sorted list.

Code

Python

C++

Java

JavaScript

Complexity

Time Complexity: O(N log N) for initialization and O(F log F) for changing rating where N is the number of foods and F is the list of foods for a cuisine.
Space Complexity: O(N) for storage of mappings.

Try this approach in the editor →

Approach 2: Using Priority Heaps

This approach uses priority queues (heaps) to manage the highest-rated food for a cuisine. Heaps offer efficient operations for maintaining and retrieving maximum values, which can be useful for finding the highest-rated item.

The Python version uses a heap to maintain the highest-rated food for each cuisine. Negative ratings are stored to utilize the min-heap structure for max-heap behavior. If ratings change, old entries may remain invalid due to imposition of new valid values. Therefore, we remove these as necessary during the highestRated check.

Code

Python

Java

Complexity

Time Complexity: O(N) for initialization and O(log F) for updating heap or retrieving the maximum where F is the number of foods for given cuisine.
Space Complexity: O(N) for storing the heap elements.

Try this approach in the editor →

Approach 3: Hash Table + Ordered Set

We can use a hash table d to store the foods for each cuisine, where the key is the cuisine and the value is an ordered set. Each element in the ordered set is a tuple (rating, food), sorted by rating in descending order, and if the ratings are the same, sorted by food name in lexicographical order.

We can also use a hash table g to store the rating and cuisine for each food. That is, g[food] = (rating, cuisine).

In the constructor, we iterate through foods, cuisines, and ratings, storing the rating and cuisine for each food in d and g.

In the changeRating function, we first get the original rating oldRating and cuisine cuisine of the food food, then update the rating of g[food] to newRating, remove (oldRating, food) from d[cuisine], and add (newRating, food) to d[cuisine].

In the highestRated function, we directly return the food name of the first element in d[cuisine].

In terms of time complexity, the constructor has a time complexity of O(n log n), where n is the number of foods. The other operations have a time complexity of O(log n). The space complexity is O(n).

Code

Python

Java

C++

Go

Try this approach in the editor →

Complexity Comparison

ApproachComplexity
Using Dictionaries/Hash Maps

Time Complexity: O(N log N) for initialization and O(F log F) for changing rating where N is the number of foods and F is the list of foods for a cuisine.
Space Complexity: O(N) for storage of mappings.

Using Priority Heaps

Time Complexity: O(N) for initialization and O(log F) for updating heap or retrieving the maximum where F is the number of foods for given cuisine.
Space Complexity: O(N) for storing the heap elements.

Hash Table + Ordered Set—

Detailed Complexity Analysis

ApproachTimeSpaceWhen to Use
Hash Maps + Ordered SetO(log n) update, O(1)–O(log n) queryO(n)When the language supports efficient ordered sets or balanced trees
Hash Maps + Priority Heap (Lazy Deletion)O(log n) update, O(log n) queryO(n)General case; easiest to implement with priority queues

Video Solution

Design a Food Rating System - Leetcode 2353 - Python • NeetCodeIO • 17,899 views views

Watch 9 more video solutions →

Frequently Asked Questions

Is Design a Food Rating System easy or hard?
The problem is rated Medium because it requires combining multiple data structures and maintaining ordering after updates. The challenge lies in designing a system that avoids expensive re-sorting while still returning the correct highest-rated food.
Design a Food Rating System Python/Java solution
Python solutions typically use dictionaries and the heapq module with lazy deletion. Java implementations use HashMap for mappings and PriorityQueue for cuisine ranking. Both implementations maintain O(log n) updates and queries.
How to solve Design a Food Rating System in O(log n)?
Store food information in a hash map and maintain a max heap per cuisine containing pairs of (-rating, foodName). When a rating changes, push the updated value to the heap. During highestRated queries, remove outdated heap entries until the top matches the latest rating in the hash map.
What is the best approach for Design a Food Rating System?
The most common solution uses a hash map for fast food lookups and a max heap for each cuisine to track the highest-rated food. Rating updates push a new entry into the heap, and outdated entries are removed lazily during queries. This keeps operations around O(log n) while maintaining correct ordering.
Is Design a Food Rating System asked at Google/Amazon/Meta?
Design-style data structure problems like this frequently appear in interviews at companies such as Google, Amazon, and Meta. The question evaluates understanding of heaps, hash tables, and maintaining ordered data efficiently under updates.
What data structure is used in Design a Food Rating System?
The core data structures are hash tables for constant-time food lookups and priority queues (heaps) or ordered sets to maintain ranking by rating and lexicographical order. This combination supports efficient updates and fast retrieval of the highest-rated item.
What is the time complexity of Design a Food Rating System?
With the heap-based design, both rating updates and highest-rated queries run in O(log n) time due to heap operations. Hash map lookups remain O(1). Space complexity is O(n) because the system stores all foods and their associated structures.

Ready to solve this problem?

Practice Design a Food Rating System with our built-in code editor and test cases.

Practice on FleetCode