Facebook Pixel

1418. Display Table of Food Orders in a Restaurant

MediumArrayHash TableStringOrdered SetSorting
Leetcode Link

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 name
  • tableNumber_i is the table number where the customer sits
  • foodItem_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"]]
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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:

  1. Which tables ordered food (these become our rows)
  2. What food items were ordered (these become our columns)
  3. 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:

  1. Sort the food items alphabetically for the header
  2. Sort the table numbers numerically for the rows
  3. 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 using defaultdict(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 get sorted_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 from tables[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 returns 0 for items not present, which gets converted to "0"
    • Add the completed row to ans

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 Evaluator

Example 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 set
  • O(m Γ— log m): Sorting the food items, where m is the number of unique food items
  • O(k Γ— log k): Sorting the table numbers, where k is the number of unique tables
  • O(m Γ— k): Building the result table - for each of the k tables, we iterate through m 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 is n items total
  • O(m): The items set stores unique food items
  • O(k): Each table number is stored as a key in the tables dictionary
  • O(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]
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What is an advantages of top-down dynamic programming vs bottom-up dynamic programming?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More