|
1 | | - |
2 | | - |
3 | | -# **1174. Immediate Food Delivery II** |
4 | | - |
5 | | -## **Problem Statement** |
6 | | -You are given a table `Delivery` that records food deliveries made to customers. Each row represents an order with the date it was placed and the customer’s preferred delivery date. |
7 | | - |
8 | | ---- |
9 | | - |
10 | | -## **Delivery Table** |
11 | | -``` |
12 | | -+-------------+-------------+------------+-----------------------------+ |
13 | | -| Column Name | Type | Description | |
14 | | -+-------------+-------------+----------------------------------------------+ |
15 | | -| delivery_id | int | Unique identifier for the delivery | |
16 | | -| customer_id | int | Identifier for the customer | |
17 | | -| order_date | date | Date when the order was placed | |
18 | | -| customer_pref_delivery_date | date | Customer’s preferred delivery date | |
19 | | -+-------------+-------------+----------------------------------------------+ |
20 | | -``` |
21 | | -- `delivery_id` is the **primary key**. |
22 | | -- Each customer specifies a preferred delivery date, which can be the same as or after the order date. |
23 | | - |
24 | | ---- |
25 | | - |
26 | | -## **Task:** |
27 | | -Calculate the **percentage** of customers whose **first order** is **immediate** (i.e., the order date is the same as the customer’s preferred delivery date). |
28 | | -- A customer’s **first order** is defined as the order with the **earliest order_date** for that customer. |
29 | | -- The result should be **rounded to 2 decimal places**. |
30 | | -- Return the percentage as `immediate_percentage`. |
31 | | - |
32 | | ---- |
33 | | - |
34 | | -## **Example 1:** |
35 | | - |
36 | | -### **Input:** |
37 | | -**Delivery Table** |
38 | | -``` |
39 | | -+-------------+-------------+------------+-----------------------------+ |
40 | | -| delivery_id | customer_id | order_date | customer_pref_delivery_date | |
41 | | -+-------------+-------------+------------+-----------------------------+ |
42 | | -| 1 | 1 | 2019年08月01日 | 2019年08月02日 | |
43 | | -| 2 | 2 | 2019年08月02日 | 2019年08月02日 | |
44 | | -| 3 | 1 | 2019年08月11日 | 2019年08月12日 | |
45 | | -| 4 | 3 | 2019年08月24日 | 2019年08月24日 | |
46 | | -| 5 | 3 | 2019年08月21日 | 2019年08月22日 | |
47 | | -| 6 | 2 | 2019年08月11日 | 2019年08月13日 | |
48 | | -| 7 | 4 | 2019年08月09日 | 2019年08月09日 | |
49 | | -+-------------+-------------+------------+-----------------------------+ |
50 | | -``` |
51 | | - |
52 | | -### **Output:** |
53 | | -``` |
54 | | -+----------------------+ |
55 | | -| immediate_percentage | |
56 | | -+----------------------+ |
57 | | -| 50.00 | |
58 | | -+----------------------+ |
59 | | -``` |
60 | | - |
61 | | -### **Explanation:** |
62 | | -- **Customer 1:** First order is on **2019年08月01日** (preferred: 2019年08月02日) → **Scheduled** |
63 | | -- **Customer 2:** First order is on **2019年08月02日** (preferred: 2019年08月02日) → **Immediate** |
64 | | -- **Customer 3:** First order is on **2019年08月21日** (preferred: 2019年08月22日) → **Scheduled** |
65 | | -- **Customer 4:** First order is on **2019年08月09日** (preferred: 2019年08月09日) → **Immediate** |
66 | | - |
67 | | -Out of 4 customers, 2 have immediate first orders. |
68 | | -Percentage = (2 / 4) * 100 = **50.00** |
69 | | - |
70 | | ---- |
71 | | - |
72 | | -## **SQL Solutions** |
73 | | - |
74 | | -### **1️⃣ Standard MySQL Solution** |
75 | | -```sql |
76 | | -SELECT |
77 | | - ROUND(100 * SUM(CASE |
78 | | - WHEN first_orders.order_date = first_orders.customer_pref_delivery_date THEN 1 |
79 | | - ELSE 0 |
80 | | - END) / COUNT(*), 2) AS immediate_percentage |
81 | | -FROM ( |
82 | | - -- Get the first order (earliest order_date) for each customer |
83 | | - SELECT customer_id, order_date, customer_pref_delivery_date |
84 | | - FROM Delivery |
85 | | - WHERE (customer_id, order_date) IN ( |
86 | | - SELECT customer_id, MIN(order_date) |
87 | | - FROM Delivery |
88 | | - GROUP BY customer_id |
89 | | - ) |
90 | | -) AS first_orders; |
91 | | -``` |
92 | | - |
93 | | -#### **Explanation:** |
94 | | -- **Subquery:** Retrieves the first order for each customer by selecting the minimum `order_date`. |
95 | | -- **Outer Query:** |
96 | | - - Uses a `CASE` statement to check if the `order_date` equals `customer_pref_delivery_date` (i.e., immediate order). |
97 | | - - Calculates the percentage of immediate first orders. |
98 | | - - Rounds the result to 2 decimal places. |
99 | | - |
100 | | ---- |
101 | | - |
102 | | -### **2️⃣ Window Function (SQL) Solution** |
103 | | -```sql |
104 | | -WITH RankedOrders AS ( |
105 | | - SELECT |
106 | | - customer_id, |
107 | | - order_date, |
108 | | - customer_pref_delivery_date, |
109 | | - ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date) AS rn |
110 | | - FROM Delivery |
111 | | -) |
112 | | -SELECT |
113 | | - ROUND(100 * SUM(CASE WHEN order_date = customer_pref_delivery_date THEN 1 ELSE 0 END) / COUNT(*), 2) AS immediate_percentage |
114 | | -FROM RankedOrders |
115 | | -WHERE rn = 1; |
116 | | -``` |
117 | | - |
118 | | -#### **Explanation:** |
119 | | -- **CTE `RankedOrders`:** |
120 | | - - Uses `ROW_NUMBER()` to rank orders for each customer by `order_date`. |
121 | | - - Filters for the first order of each customer (`rn = 1`). |
122 | | -- **Final SELECT:** |
123 | | - - Computes the percentage of first orders that are immediate. |
124 | | - - Rounds the result to 2 decimal places. |
125 | | - |
126 | | ---- |
127 | | - |
128 | | -## **Pandas Solution (Python)** |
129 | | -```python |
130 | | -import pandas as pd |
131 | | - |
132 | | -def immediate_food_delivery_percentage(delivery: pd.DataFrame) -> pd.DataFrame: |
133 | | - # Ensure order_date and customer_pref_delivery_date are in datetime format |
134 | | - delivery['order_date'] = pd.to_datetime(delivery['order_date']) |
135 | | - delivery['customer_pref_delivery_date'] = pd.to_datetime(delivery['customer_pref_delivery_date']) |
136 | | - |
137 | | - # Get the first order date for each customer |
138 | | - first_order = delivery.groupby('customer_id')['order_date'].min().reset_index() |
139 | | - first_order = first_order.rename(columns={'order_date': 'first_order_date'}) |
140 | | - |
141 | | - # Merge to get the corresponding preferred delivery date for the first order |
142 | | - merged = pd.merge(delivery, first_order, on='customer_id', how='inner') |
143 | | - first_orders = merged[merged['order_date'] == merged['first_order_date']] |
144 | | - |
145 | | - # Calculate immediate orders |
146 | | - immediate_count = (first_orders['order_date'] == first_orders['customer_pref_delivery_date']).sum() |
147 | | - total_customers = first_orders['customer_id'].nunique() |
148 | | - immediate_percentage = round(100 * immediate_count / total_customers, 2) |
149 | | - |
150 | | - return pd.DataFrame({'immediate_percentage': [immediate_percentage]}) |
151 | | - |
152 | | -# Example usage: |
153 | | -# df = pd.read_csv('delivery.csv') |
154 | | -# print(immediate_food_delivery_percentage(df)) |
155 | | -``` |
156 | | - |
157 | | -#### **Explanation:** |
158 | | -- **Convert Dates:** |
159 | | - - Convert `order_date` and `customer_pref_delivery_date` to datetime for accurate comparison. |
160 | | -- **Determine First Order:** |
161 | | - - Group by `customer_id` to find the minimum `order_date` as the first order. |
162 | | - - Merge with the original DataFrame to obtain details of the first order. |
163 | | -- **Calculate Percentage:** |
164 | | - - Count how many first orders are immediate (where `order_date` equals `customer_pref_delivery_date`). |
165 | | - - Compute the percentage and round to 2 decimal places. |
166 | | - |
167 | | ---- |
168 | | - |
169 | | -## **File Structure** |
170 | | -``` |
171 | | -LeetCode1174/ |
172 | | -├── problem_statement.md # Contains the problem description and constraints. |
173 | | -├── sql_standard_solution.sql # Contains the Standard MySQL solution. |
174 | | -├── sql_window_solution.sql # Contains the Window Function solution. |
175 | | -├── pandas_solution.py # Contains the Pandas solution. |
176 | | -├── README.md # Overview of the problem and available solutions. |
177 | | -``` |
178 | | - |
179 | | ---- |
180 | | - |
181 | | -## **Useful Links** |
182 | | -- [LeetCode Problem 1174](https://leetcode.com/problems/immediate-food-delivery-ii/) |
183 | | -- [SQL GROUP BY Documentation](https://www.w3schools.com/sql/sql_groupby.asp) |
184 | | -- [SQL Window Functions](https://www.w3schools.com/sql/sql_window.asp) |
185 | | -- [Pandas GroupBy Documentation](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html) |
186 | | -- [Pandas Merge Documentation](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.merge.html) |
0 commit comments