Skip to content

Commit 70d6eae

Browse files
authored
feat: add solutions to lc problems: No.3705,3706 (#4767)
* feat: add solutions to lc problem: No.3705 * feat: add solutions to lc problem: No.3706
1 parent a94b7fe commit 70d6eae

File tree

16 files changed

+973
-1
lines changed

16 files changed

+973
-1
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
---
2+
comments: true
3+
difficulty: 中等
4+
edit_url: https://github.com/doocs/leetcode/edit/main/solution/3700-3799/3705.Find%20Golden%20Hour%20Customers/README.md
5+
tags:
6+
- 数据库
7+
---
8+
9+
<!-- problem:start -->
10+
11+
# [3705. Find Golden Hour Customers](https://leetcode.cn/problems/find-golden-hour-customers)
12+
13+
[English Version](/solution/3700-3799/3705.Find%20Golden%20Hour%20Customers/README_EN.md)
14+
15+
## 题目描述
16+
17+
<!-- description:start -->
18+
19+
<p>Table: <code>restaurant_orders</code></p>
20+
21+
<pre>
22+
+------------------+----------+
23+
| Column Name | Type |
24+
+------------------+----------+
25+
| order_id | int |
26+
| customer_id | int |
27+
| order_timestamp | datetime |
28+
| order_amount | decimal |
29+
| payment_method | varchar |
30+
| order_rating | int |
31+
+------------------+----------+
32+
order_id is the unique identifier for this table.
33+
payment_method can be cash, card, or app.
34+
order_rating is between 1 and 5, where 5 is the best (NULL if not rated).
35+
order_timestamp contains both date and time information.
36+
</pre>
37+
38+
<p>Write a solution to find <strong>golden hour customers</strong>&nbsp;- customers who consistently order during peak hours and provide high satisfaction. A customer is a <strong>golden hour customer</strong> if they meet ALL the following criteria:</p>
39+
40+
<ul>
41+
<li>Made <strong>at least</strong> <code>3</code> orders.</li>
42+
<li><strong>At least</strong> <code>60%</code> of their orders are during <strong>peak hours&nbsp;</strong>(<code>11:00</code>-<code>14:00</code> or <code>18:00</code>-<code>21:00</code>).</li>
43+
<li>Their <strong>average rating</strong> for rated orders is at least <code>4.0,</code> round it to<code> 2 </code>decimal places.</li>
44+
<li>Have rated <strong>at least</strong> <code>50%</code> of their orders.</li>
45+
</ul>
46+
47+
<p>Return <em>the result table ordered by</em> <code>average_rating</code> <em>in <strong>descending</strong> order, then by</em> <code>customer_id</code>​​​​​​​ <em>in <strong>descending</strong> order</em>.</p>
48+
49+
<p>The result format is in the following example.</p>
50+
51+
<p>&nbsp;</p>
52+
<p><strong class="example">Example:</strong></p>
53+
54+
<div class="example-block">
55+
<p><strong>Input:</strong></p>
56+
57+
<p>restaurant_orders table:</p>
58+
59+
<pre class="example-io">
60+
+----------+-------------+---------------------+--------------+----------------+--------------+
61+
| order_id | customer_id | order_timestamp | order_amount | payment_method | order_rating |
62+
+----------+-------------+---------------------+--------------+----------------+--------------+
63+
| 1 | 101 | 2024-03-01 12:30:00 | 25.50 | card | 5 |
64+
| 2 | 101 | 2024-03-02 19:15:00 | 32.00 | app | 4 |
65+
| 3 | 101 | 2024-03-03 13:45:00 | 28.75 | card | 5 |
66+
| 4 | 101 | 2024-03-04 20:30:00 | 41.00 | app | NULL |
67+
| 5 | 102 | 2024-03-01 11:30:00 | 18.50 | cash | 4 |
68+
| 6 | 102 | 2024-03-02 12:00:00 | 22.00 | card | 3 |
69+
| 7 | 102 | 2024-03-03 15:30:00 | 19.75 | cash | NULL |
70+
| 8 | 103 | 2024-03-01 19:00:00 | 55.00 | app | 5 |
71+
| 9 | 103 | 2024-03-02 20:45:00 | 48.50 | app | 4 |
72+
| 10 | 103 | 2024-03-03 18:30:00 | 62.00 | card | 5 |
73+
| 11 | 104 | 2024-03-01 10:00:00 | 15.00 | cash | 3 |
74+
| 12 | 104 | 2024-03-02 09:30:00 | 18.00 | cash | 2 |
75+
| 13 | 104 | 2024-03-03 16:00:00 | 20.00 | card | 3 |
76+
| 14 | 105 | 2024-03-01 12:15:00 | 30.00 | app | 4 |
77+
| 15 | 105 | 2024-03-02 13:00:00 | 35.50 | app | 5 |
78+
| 16 | 105 | 2024-03-03 11:45:00 | 28.00 | card | 4 |
79+
+----------+-------------+---------------------+--------------+----------------+--------------+
80+
</pre>
81+
82+
<p><strong>Output:</strong></p>
83+
84+
<pre class="example-io">
85+
+-------------+--------------+----------------------+----------------+
86+
| customer_id | total_orders | peak_hour_percentage | average_rating |
87+
+-------------+--------------+----------------------+----------------+
88+
| 103 | 3 | 100 | 4.67 |
89+
| 101 | 4 | 75 | 4.67 |
90+
| 105 | 3 | 100 | 4.33 |
91+
+-------------+--------------+----------------------+----------------+
92+
</pre>
93+
94+
<p><strong>Explanation:</strong></p>
95+
96+
<ul>
97+
<li><strong>Customer 101</strong>:
98+
99+
<ul>
100+
<li>Total orders: 4 (at least 3)&nbsp;</li>
101+
<li>Peak hour orders: 3 out of 4 (12:30, 19:15, 13:45, and 20:30 are in peak hours)</li>
102+
<li>Peak hour percentage: 3/4 = 75% (at least 60%)&nbsp;</li>
103+
<li>Rated orders: 3 out of 4 (75% rating completion)&nbsp;</li>
104+
<li>Average rating: (5+4+5)/3 = 4.67 (at least 4.0)&nbsp;</li>
105+
<li>Result: <strong>Golden hour customer</strong></li>
106+
</ul>
107+
</li>
108+
<li><strong>Customer 102</strong>:
109+
<ul>
110+
<li>Total orders: 3 (at least 3)&nbsp;</li>
111+
<li>Peak hour orders: 2 out of 3 (11:30, 12:00 are in peak hours; 15:30 is not)</li>
112+
<li>Peak hour percentage: 2/3 = 66.67% (at least 60%)&nbsp;</li>
113+
<li>Rated orders: 2 out of 3 (66.67% rating completion)&nbsp;</li>
114+
<li>Average rating: (4+3)/2 = 3.5 (less than 4.0)&nbsp;</li>
115+
<li>Result: <strong>Not a golden hour customer</strong> (average rating too low)</li>
116+
</ul>
117+
</li>
118+
<li><strong>Customer 103</strong>:
119+
<ul>
120+
<li>Total orders: 3 (at least 3)&nbsp;</li>
121+
<li>Peak hour orders: 3 out of 3 (19:00, 20:45, 18:30 all in evening peak)</li>
122+
<li>Peak hour percentage: 3/3 = 100% (at least 60%)&nbsp;</li>
123+
<li>Rated orders: 3 out of 3 (100% rating completion)&nbsp;</li>
124+
<li>Average rating: (5+4+5)/3 = 4.67 (at least 4.0)&nbsp;</li>
125+
<li>Result: <strong>Golden hour customer</strong></li>
126+
</ul>
127+
</li>
128+
<li><strong>Customer 104</strong>:
129+
<ul>
130+
<li>Total orders: 3 (at least 3)&nbsp;</li>
131+
<li>Peak hour orders: 0 out of 3 (10:00, 09:30, 16:00 all outside peak hours)</li>
132+
<li>Peak hour percentage: 0/3 = 0% (less than 60%)&nbsp;</li>
133+
<li>Result: <strong>Not a golden hour customer</strong> (insufficient peak hour orders)</li>
134+
</ul>
135+
</li>
136+
<li><strong>Customer 105</strong>:
137+
<ul>
138+
<li>Total orders: 3 (at least 3)&nbsp;</li>
139+
<li>Peak hour orders: 3 out of 3 (12:15, 13:00, 11:45 all in lunch peak)</li>
140+
<li>Peak hour percentage: 3/3 = 100% (at least 60%)&nbsp;</li>
141+
<li>Rated orders: 3 out of 3 (100% rating completion)&nbsp;</li>
142+
<li>Average rating: (4+5+4)/3 = 4.33 (at least 4.0)&nbsp;</li>
143+
<li>Result: <strong>Golden hour customer</strong></li>
144+
</ul>
145+
</li>
146+
147+
</ul>
148+
149+
<p>The results table is ordered by average_rating DESC, then customer_id DESC.</p>
150+
</div>
151+
152+
<!-- description:end -->
153+
154+
## 解法
155+
156+
<!-- solution:start -->
157+
158+
### 方法一:分组统计
159+
160+
我们可以将订单按照 `customer_id` 进行分组,统计每个顾客的总订单数、峰值时段订单数、评分订单数和平均评分,然后根据题目中的条件进行筛选,最后按照平均评分降序、顾客 ID 降序排序。
161+
162+
<!-- tabs:start -->
163+
164+
#### MySQL
165+
166+
```sql
167+
# Write your MySQL query statement below
168+
SELECT
169+
customer_id,
170+
COUNT(1) total_orders,
171+
ROUND(
172+
SUM(
173+
TIME(order_timestamp) BETWEEN '11:00:00' AND '14:00:00'
174+
OR TIME(order_timestamp) BETWEEN '18:00:00' AND '21:00:00'
175+
) / COUNT(1) * 100
176+
) peak_hour_percentage,
177+
ROUND(AVG(order_rating), 2) average_rating
178+
FROM restaurant_orders
179+
GROUP BY customer_id
180+
HAVING
181+
total_orders >= 3
182+
AND peak_hour_percentage >= 60
183+
AND average_rating >= 4.0
184+
AND SUM(order_rating IS NOT NULL) / total_orders >= 0.5
185+
ORDER BY average_rating DESC, customer_id DESC;
186+
```
187+
188+
#### Pandas
189+
190+
```python
191+
import pandas as pd
192+
import numpy as np
193+
194+
195+
def find_golden_hour_customers(restaurant_orders: pd.DataFrame) -> pd.DataFrame:
196+
df = restaurant_orders.copy()
197+
df["order_timestamp"] = pd.to_datetime(df["order_timestamp"])
198+
df["is_peak_hour"] = df["order_timestamp"].dt.time.between(
199+
pd.to_datetime("11:00:00").time(), pd.to_datetime("14:00:00").time()
200+
) | df["order_timestamp"].dt.time.between(
201+
pd.to_datetime("18:00:00").time(), pd.to_datetime("21:00:00").time()
202+
)
203+
grouped = (
204+
df.groupby("customer_id")
205+
.agg(
206+
total_orders=("order_timestamp", "count"),
207+
peak_hour_count=("is_peak_hour", "sum"),
208+
average_rating=("order_rating", lambda x: x.dropna().mean()),
209+
non_null_rating_count=("order_rating", lambda x: x.notna().sum()),
210+
)
211+
.reset_index()
212+
)
213+
grouped["average_rating"] = grouped["average_rating"].round(2)
214+
grouped["peak_hour_percentage"] = (
215+
grouped["peak_hour_count"] / grouped["total_orders"] * 100
216+
).round()
217+
filtered = grouped[
218+
(grouped["total_orders"] >= 3)
219+
& (grouped["peak_hour_percentage"] >= 60)
220+
& (grouped["average_rating"] >= 4.0)
221+
& (grouped["non_null_rating_count"] / grouped["total_orders"] >= 0.5)
222+
]
223+
filtered = filtered.sort_values(
224+
by=["average_rating", "customer_id"], ascending=[False, False]
225+
)
226+
return filtered[
227+
["customer_id", "total_orders", "peak_hour_percentage", "average_rating"]
228+
]
229+
```
230+
231+
<!-- tabs:end -->
232+
233+
<!-- solution:end -->
234+
235+
<!-- problem:end -->

0 commit comments

Comments
 (0)