1418. Display Table of Food Orders in a Restaurant
Problem Description
You are given an array orders
representing customer orders in a restaurant. Each order is formatted as orders[i] = [customerName_i, tableNumber_i, foodItem_i]
where:
customerName_i
is the customer's nametableNumber_i
is the table number where the customer sitsfoodItem_i
is the food item the customer ordered
Your task is to create a "display table" that shows how many of each food item was ordered at each table.
The display table should be structured as follows:
- The first row is a header row starting with
"Table"
, followed by all unique food items sorted in alphabetical order - Each subsequent row represents a table:
- The first column contains the table number (as a string)
- The remaining columns contain the count of each food item ordered at that table (as strings)
- If a food item wasn't ordered at a table, the count should be
"0"
- Tables should be sorted in numerically increasing order
Note that customer names are not included in the display table - only table numbers and food item counts matter.
For example, if table 3 ordered 2 "Beef Burrito" and 1 "Ceviche", and table 5 ordered 1 "Beef Burrito", the display table would look like:
[["Table", "Beef Burrito", "Ceviche"], ["3", "2", "1"], ["5", "1", "0"]]
Intuition
The key insight is that we need to transform the raw order data into a structured table format. Think of it like creating a summary report for a restaurant manager.
First, we need to identify what information we're tracking:
- Which tables ordered food (these become our rows)
- What food items were ordered (these become our columns)
- How many of each item each table ordered (these become our cell values)
Since we need all unique food items as columns in alphabetical order, we should collect all food items in a set to automatically handle duplicates. For the table data, we need to group orders by table number - a hash table (dictionary) is perfect for this, where each table number maps to its list of ordered items.
The challenge is that different tables might order different items, but our display table needs to show all items for all tables (with "0"
for items not ordered). This means after collecting the data, we need to:
- Sort the food items alphabetically for the header
- Sort the table numbers numerically for the rows
- Count occurrences of each food item per table
Using a Counter
for each table's orders makes counting straightforward. For each table, we iterate through all possible food items (not just what that table ordered) and look up the count, which naturally gives us 0
for items not ordered.
The structure naturally leads to a two-phase approach: first collect and organize the data, then format it into the required display table structure.
Learn more about Sorting patterns.
Solution Approach
We implement the solution using hash tables and sorting as follows:
Step 1: Initialize Data Structures
- Create a hash table
tables
usingdefaultdict(list)
to store the list of food items ordered at each table - Create a set
items
to store all unique food items across all orders
Step 2: Process Orders
Iterate through each order in orders
:
- Extract the table number and food item (ignore customer name)
- Convert table number to integer and append the food item to
tables[int(table)]
- Add the food item to the
items
set
Step 3: Sort Food Items
- Sort the
items
set alphabetically to getsorted_items
- This gives us the column order for our display table
Step 4: Build the Display Table
- Initialize the answer array
ans
with the header row:["Table"] + sorted_items
- Iterate through tables in numerically sorted order using
sorted(tables)
:- For each table, create a
Counter
fromtables[table]
to count occurrences of each food item - Build a row starting with the table number as a string:
str(table)
- For each food item in
sorted_items
, append the count as a string:str(cnt[item])
- The
Counter
automatically returns0
for items not present, which gets converted to"0"
- Add the completed row to
ans
- For each table, create a
Step 5: Return Result
- Return the completed
ans
array representing the display table
The time complexity is O(N + M log M + T log T)
where N
is the number of orders, M
is the number of unique food items, and T
is the number of tables. The space complexity is O(N)
for storing the orders in our data structures.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with the following orders:
orders = [["David","3","Ceviche"], ["Corina","10","Beef Burrito"], ["David","3","Fried Chicken"], ["Carla","5","Water"], ["Carla","5","Ceviche"], ["Rous","3","Ceviche"]]
Step 1: Initialize Data Structures
tables = defaultdict(list)
(empty initially)items = set()
(empty initially)
Step 2: Process Orders
Processing each order:
- Order 1:
["David","3","Ceviche"]
βtables[3] = ["Ceviche"]
,items = {"Ceviche"}
- Order 2:
["Corina","10","Beef Burrito"]
βtables[10] = ["Beef Burrito"]
,items = {"Ceviche", "Beef Burrito"}
- Order 3:
["David","3","Fried Chicken"]
βtables[3] = ["Ceviche", "Fried Chicken"]
,items = {"Ceviche", "Beef Burrito", "Fried Chicken"}
- Order 4:
["Carla","5","Water"]
βtables[5] = ["Water"]
,items = {"Ceviche", "Beef Burrito", "Fried Chicken", "Water"}
- Order 5:
["Carla","5","Ceviche"]
βtables[5] = ["Water", "Ceviche"]
, items unchanged - Order 6:
["Rous","3","Ceviche"]
βtables[3] = ["Ceviche", "Fried Chicken", "Ceviche"]
, items unchanged
After processing:
tables = {3: ["Ceviche", "Fried Chicken", "Ceviche"], 5: ["Water", "Ceviche"], 10: ["Beef Burrito"]}
items = {"Ceviche", "Beef Burrito", "Fried Chicken", "Water"}
Step 3: Sort Food Items
sorted_items = ["Beef Burrito", "Ceviche", "Fried Chicken", "Water"]
(alphabetical order)
Step 4: Build the Display Table
Header row: ["Table", "Beef Burrito", "Ceviche", "Fried Chicken", "Water"]
Process tables in numerical order (3, 5, 10):
Table 3:
- Counter:
{"Ceviche": 2, "Fried Chicken": 1}
- Row:
["3", "0", "2", "1", "0"]
Table 5:
- Counter:
{"Water": 1, "Ceviche": 1}
- Row:
["5", "0", "1", "0", "1"]
Table 10:
- Counter:
{"Beef Burrito": 1}
- Row:
["10", "1", "0", "0", "0"]
Step 5: Return Result
[["Table", "Beef Burrito", "Ceviche", "Fried Chicken", "Water"], ["3", "0", "2", "1", "0"], ["5", "0", "1", "0", "1"], ["10", "1", "0", "0", "0"]]
Notice how the Counter automatically provides "0" for items not ordered at each table, and all values are strings as required.
Solution Implementation
1from typing import List
2from collections import defaultdict, Counter
3
4class Solution:
5 def displayTable(self, orders: List[List[str]]) -> List[List[str]]:
6 # Dictionary to store food items for each table
7 # Key: table number (int), Value: list of food items
8 table_orders = defaultdict(list)
9
10 # Set to store all unique food items
11 food_items = set()
12
13 # Process each order to populate table_orders and food_items
14 for customer_name, table_number, food_item in orders:
15 table_orders[int(table_number)].append(food_item)
16 food_items.add(food_item)
17
18 # Sort food items alphabetically for column headers
19 sorted_food_items = sorted(food_items)
20
21 # Initialize result with header row
22 result = [["Table"] + sorted_food_items]
23
24 # Process each table in ascending order
25 for table_number in sorted(table_orders):
26 # Count occurrences of each food item for current table
27 food_count = Counter(table_orders[table_number])
28
29 # Build row: table number followed by count for each food item
30 row = [str(table_number)] + [str(food_count[food_item]) for food_item in sorted_food_items]
31 result.append(row)
32
33 return result
34
1class Solution {
2 public List<List<String>> displayTable(List<List<String>> orders) {
3 // TreeMap to store tables in sorted order (by table number)
4 // Key: table number, Value: list of food items ordered at that table
5 TreeMap<Integer, List<String>> tableToFoodItems = new TreeMap<>();
6
7 // Set to store all unique food items across all orders
8 Set<String> uniqueFoodItems = new HashSet<>();
9
10 // Process each order to populate the data structures
11 for (List<String> order : orders) {
12 // Extract table number and food item from the order
13 // Order format: [customerName, tableNumber, foodItem]
14 int tableNumber = Integer.parseInt(order.get(1));
15 String foodItem = order.get(2);
16
17 // Add food item to the table's list of orders
18 tableToFoodItems.computeIfAbsent(tableNumber, k -> new ArrayList<>()).add(foodItem);
19
20 // Add food item to the set of unique items
21 uniqueFoodItems.add(foodItem);
22 }
23
24 // Sort food items alphabetically for consistent column ordering
25 List<String> sortedFoodItems = new ArrayList<>(uniqueFoodItems);
26 Collections.sort(sortedFoodItems);
27
28 // Initialize the result table
29 List<List<String>> resultTable = new ArrayList<>();
30
31 // Create and add the header row
32 List<String> headerRow = new ArrayList<>();
33 headerRow.add("Table");
34 headerRow.addAll(sortedFoodItems);
35 resultTable.add(headerRow);
36
37 // Process each table to create data rows
38 for (Map.Entry<Integer, List<String>> tableEntry : tableToFoodItems.entrySet()) {
39 // Count occurrences of each food item for the current table
40 Map<String, Integer> foodItemCount = new HashMap<>();
41 for (String foodItem : tableEntry.getValue()) {
42 foodItemCount.merge(foodItem, 1, Integer::sum);
43 }
44
45 // Build the row for the current table
46 List<String> tableRow = new ArrayList<>();
47
48 // Add table number as the first column
49 tableRow.add(String.valueOf(tableEntry.getKey()));
50
51 // Add count for each food item in the sorted order
52 for (String foodItem : sortedFoodItems) {
53 // Get count or 0 if the item wasn't ordered at this table
54 tableRow.add(String.valueOf(foodItemCount.getOrDefault(foodItem, 0)));
55 }
56
57 resultTable.add(tableRow);
58 }
59
60 return resultTable;
61 }
62}
63
1class Solution {
2public:
3 vector<vector<string>> displayTable(vector<vector<string>>& orders) {
4 // Map to store table number as key and list of food items as value
5 // Using map instead of unordered_map to keep tables sorted by number
6 map<int, vector<string>> tableToFoodItems;
7
8 // Set to store all unique food items in alphabetical order
9 set<string> uniqueFoodItems;
10
11 // Process each order to populate the data structures
12 for (auto& order : orders) {
13 int tableNumber = stoi(order[1]);
14 string foodItem = order[2];
15
16 // Add food item to the corresponding table
17 tableToFoodItems[tableNumber].push_back(foodItem);
18
19 // Add food item to the set of unique items
20 uniqueFoodItems.insert(foodItem);
21 }
22
23 // Result vector to store the display table
24 vector<vector<string>> displayResult;
25
26 // Create header row with "Table" followed by sorted food items
27 vector<string> headerRow = {"Table"};
28 headerRow.insert(headerRow.end(), uniqueFoodItems.begin(), uniqueFoodItems.end());
29 displayResult.push_back(headerRow);
30
31 // Process each table to create its corresponding row
32 for (auto& [tableNumber, foodItemsList] : tableToFoodItems) {
33 // Count frequency of each food item for current table
34 unordered_map<string, int> foodItemCount;
35 for (string& foodItem : foodItemsList) {
36 foodItemCount[foodItem]++;
37 }
38
39 // Build row for current table
40 vector<string> currentRow;
41 currentRow.push_back(to_string(tableNumber));
42
43 // Add count for each food item in the same order as header
44 for (const string& foodItem : uniqueFoodItems) {
45 currentRow.push_back(to_string(foodItemCount[foodItem]));
46 }
47
48 displayResult.push_back(currentRow);
49 }
50
51 return displayResult;
52 }
53};
54
1/**
2 * Creates a display table showing the count of food items ordered at each table
3 * @param orders - Array of orders where each order is [customerName, tableNumber, foodItem]
4 * @returns 2D array representing the display table with header row and data rows
5 */
6function displayTable(orders: string[][]): string[][] {
7 // Store table orders: tableNumber -> foodItem -> count
8 const tableOrders: Record<number, Record<string, number>> = {};
9
10 // Track all unique food items
11 const foodItems: Set<string> = new Set();
12
13 // Process each order to build table data
14 for (const [customerName, tableNumber, foodItem] of orders) {
15 // Convert table number from string to number
16 const tableNum: number = Number(tableNumber);
17
18 // Initialize table record if it doesn't exist
19 if (!tableOrders[tableNum]) {
20 tableOrders[tableNum] = {};
21 }
22
23 // Initialize food item count if it doesn't exist for this table
24 if (!tableOrders[tableNum][foodItem]) {
25 tableOrders[tableNum][foodItem] = 0;
26 }
27
28 // Increment the count for this food item at this table
29 tableOrders[tableNum][foodItem]++;
30
31 // Add food item to the set of all items
32 foodItems.add(foodItem);
33 }
34
35 // Sort food items alphabetically for column headers
36 const sortedFoodItems: string[] = Array.from(foodItems).sort();
37
38 // Initialize result array
39 const result: string[][] = [];
40
41 // Create header row with "Table" followed by sorted food items
42 const headerRow: string[] = ['Table', ...sortedFoodItems];
43 result.push(headerRow);
44
45 // Get sorted table numbers in ascending order
46 const sortedTableNumbers: number[] = Object.keys(tableOrders)
47 .map(Number)
48 .sort((a, b) => a - b);
49
50 // Build data rows for each table
51 for (const tableNum of sortedTableNumbers) {
52 // Start row with table number
53 const dataRow: string[] = [tableNum.toString()];
54
55 // Add count for each food item (0 if not ordered at this table)
56 for (const foodItem of sortedFoodItems) {
57 const count: number = tableOrders[tableNum][foodItem] || 0;
58 dataRow.push(count.toString());
59 }
60
61 result.push(dataRow);
62 }
63
64 return result;
65}
66
Time and Space Complexity
Time Complexity: O(n + m Γ log m + k Γ log k + m Γ k)
Breaking down the time complexity:
O(n)
: Iterating through all orders to populate the tables dictionary and items setO(m Γ log m)
: Sorting the food items, wherem
is the number of unique food itemsO(k Γ log k)
: Sorting the table numbers, wherek
is the number of unique tablesO(m Γ k)
: Building the result table - for each of thek
tables, we iterate throughm
food items to get their counts
The dominant term depends on the relationship between n
, m
, and k
, but all operations are necessary for the algorithm.
Space Complexity: O(n + m + k)
Breaking down the space complexity:
O(n)
: The tables dictionary stores all food items ordered, which in worst case isn
items totalO(m)
: The items set stores unique food itemsO(k)
: Each table number is stored as a key in the tables dictionaryO(m Γ k)
: The output answer array has dimensions of(k+1) Γ (m+1)
Since the output space O(m Γ k)
is required for the answer and cannot be optimized away, the overall space complexity considering extra space used is O(n + m + k)
as the reference indicates, where the output space is not counted as extra space.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect Data Type Handling for Table Numbers
A frequent mistake is forgetting to convert table numbers between integers and strings at the appropriate times. The input provides table numbers as strings, but they need to be sorted numerically (not lexicographically), and then converted back to strings for the output.
Incorrect approach:
# This would sort tables lexicographically: "10", "2", "3" instead of "2", "3", "10"
for table_number in sorted(table_orders.keys()):
# If table_orders keys are strings, this sorts incorrectly
Correct approach:
# Convert to int when storing, sort as integers, convert back to string for output
table_orders[int(table_number)].append(food_item) # Store with int key
for table_number in sorted(table_orders): # Sort numerically
row = [str(table_number)] + ... # Convert back to string for output
2. Missing Zero Counts for Unordered Items
Another common error is forgetting to include "0" counts for food items that weren't ordered at a particular table. Some developers might only include the items that were actually ordered.
Incorrect approach:
# Only includes items that were ordered at this table
row = [str(table_number)]
for food_item in table_orders[table_number]:
row.append(str(count_of_item))
Correct approach:
# Iterates through ALL food items, Counter returns 0 for missing items
food_count = Counter(table_orders[table_number])
row = [str(table_number)] + [str(food_count[food_item]) for food_item in sorted_food_items]
3. Forgetting to Sort Food Items Alphabetically
The problem specifically requires food items to be sorted alphabetically in the header row. Using an unsorted set or list would produce incorrect column ordering.
Incorrect approach:
# Using food_items directly without sorting
result = [["Table"] + list(food_items)] # Order is undefined
Correct approach:
sorted_food_items = sorted(food_items)
result = [["Table"] + sorted_food_items]
What is an advantages of top-down dynamic programming vs bottom-up dynamic programming?
Recommended Readings
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!