LeetCode 1355 - Activity Participants
This problem asks us to analyze participation counts for different activities and return only the activities whose parti
Difficulty: 🟡 Medium
Topics: Database
Solution
Problem Understanding
This problem asks us to analyze participation counts for different activities and return only the activities whose participant counts are neither the highest nor the lowest among all activities.
We are given two database tables:
The Friends table records which friend participates in which activity. Each row represents one friend and exactly one activity.
The Activities table contains the list of all activities.
The key observation is that every activity listed in Activities is guaranteed to appear in Friends, which means every activity has at least one participant. This guarantee simplifies the solution because we do not need to handle activities with zero participants.
The task is to compute how many friends participate in each activity, determine:
- the maximum participant count
- the minimum participant count
and then return all activities whose counts are strictly between those two values.
For the sample input:
| Activity | Participants |
|---|---|
| Eating | 3 |
| Singing | 2 |
| Horse Riding | 1 |
The maximum count is 3, the minimum count is 1, and only Singing has a count that is neither maximum nor minimum.
An important detail is that multiple activities may share the same maximum or minimum count. Every activity with the maximum count must be excluded, and every activity with the minimum count must also be excluded.
The output may be returned in any order, so sorting is unnecessary unless explicitly requested.
Because this is a SQL database problem, the main challenge is constructing the correct aggregation and filtering logic using SQL operations such as:
GROUP BY- aggregate functions like
COUNT - subqueries or common table expressions
- filtering based on computed aggregates
Several edge cases are important:
- If all activities have the same number of participants, then every activity is simultaneously both maximum and minimum, so the result is empty.
- Multiple activities can tie for maximum participation.
- Multiple activities can tie for minimum participation.
- There may be only two distinct participation counts, in which case no activity qualifies.
- Since every activity appears in
Friends, we never need to handle null counts or missing joins.
Approaches
Brute Force Approach
A straightforward approach is to compute the participant count for every activity, store those counts, and then repeatedly compare each activity against all others to determine whether it has the maximum or minimum count.
The process would look like this:
- Count participants for every activity.
- For each activity:
- Scan all other activities to determine whether its count is the maximum.
- Scan all other activities again to determine whether its count is the minimum.
- Include the activity only if it is neither.
This works because every activity is explicitly compared against every other activity, guaranteeing correct identification of maximum and minimum counts.
However, this approach is inefficient because for n activities, each activity may compare itself against all others, leading to quadratic behavior.
Optimal Approach
The better solution is based on aggregation.
The key insight is that we only need three pieces of information:
- The participant count for every activity
- The global maximum participant count
- The global minimum participant count
Once we know these values, filtering becomes simple.
We first group the Friends table by activity and compute counts. Then we calculate the maximum and minimum counts across those grouped results. Finally, we return only the activities whose counts are not equal to either extreme.
This approach avoids repeated comparisons and performs aggregation only once.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n²) | O(n) | Repeatedly compares every activity against all others |
| Optimal | O(n) | O(n) | Uses aggregation once, then filters efficiently |
Algorithm Walkthrough
- Group the
Friendstable byactivity.
We need to know how many participants belong to each activity. Using GROUP BY activity allows SQL to collect all rows for the same activity together.
2. Compute the participant count for each group.
Using COUNT(*), we calculate the number of friends participating in each activity.
Example intermediate result:
| activity | cnt |
|---|---|
| Eating | 3 |
| Singing | 2 |
| Horse Riding | 1 |
| 3. Determine the maximum participant count. |
We apply MAX(cnt) over the grouped counts. In the example above, the maximum is 3.
4. Determine the minimum participant count.
We apply MIN(cnt) over the grouped counts. In the example above, the minimum is 1.
5. Filter activities whose counts are neither maximum nor minimum.
We keep only rows where:
cnt != max_cnt AND cnt != min_cnt
- Return the activity names.
The final result contains only the qualifying activities.
Why it works
The algorithm works because every activity is assigned exactly one participation count. The global maximum and minimum counts fully define which activities must be excluded. Any activity whose count differs from both extremes necessarily lies strictly between them, so it satisfies the problem requirements.
Python Solution
Although this is a database problem, LeetCode database solutions are written in SQL. The following represents the correct SQL solution embedded in Python string form for completeness.
class Solution:
def activityParticipants(self):
return """
WITH activity_counts AS (
SELECT
activity,
COUNT(*) AS participant_count
FROM Friends
GROUP BY activity
)
SELECT activity
FROM activity_counts
WHERE participant_count NOT IN (
(SELECT MAX(participant_count) FROM activity_counts),
(SELECT MIN(participant_count) FROM activity_counts)
);
"""
The solution first creates a common table expression named activity_counts. This intermediate result stores each activity together with its participant count.
Next, the outer query filters the rows. The MAX and MIN subqueries compute the largest and smallest participation counts from the aggregated table.
Finally, the NOT IN condition removes all activities whose counts match either extreme.
Using a common table expression improves readability because the aggregation logic is written only once.
Go Solution
Again, because this is a database problem, the actual accepted solution is SQL. The following Go representation simply returns the SQL query.
package main
type Solution struct{}
func (s Solution) ActivityParticipants() string {
return `
WITH activity_counts AS (
SELECT
activity,
COUNT(*) AS participant_count
FROM Friends
GROUP BY activity
)
SELECT activity
FROM activity_counts
WHERE participant_count NOT IN (
(SELECT MAX(participant_count) FROM activity_counts),
(SELECT MIN(participant_count) FROM activity_counts)
);
`
}
The Go version mirrors the Python version exactly. Since the problem is fundamentally SQL-based, the Go code simply stores and returns the query string.
There are no concerns about integer overflow, slices, arrays, or nil handling because all computation occurs inside the SQL engine.
Worked Examples
Example 1
Input tables:
Friends
| id | name | activity |
|---|---|---|
| 1 | Jonathan D. | Eating |
| 2 | Jade W. | Singing |
| 3 | Victor J. | Singing |
| 4 | Elvis Q. | Eating |
| 5 | Daniel A. | Eating |
| 6 | Bob B. | Horse Riding |
Step 1: Group by activity
| activity | participants |
|---|---|
| Eating | Jonathan D., Elvis Q., Daniel A. |
| Singing | Jade W., Victor J. |
| Horse Riding | Bob B. |
Step 2: Count participants
| activity | count |
|---|---|
| Eating | 3 |
| Singing | 2 |
| Horse Riding | 1 |
Step 3: Compute maximum and minimum
| Metric | Value |
|---|---|
| Maximum | 3 |
| Minimum | 1 |
Step 4: Filter activities
| activity | count | Keep? |
|---|---|---|
| Eating | 3 | No, maximum |
| Singing | 2 | Yes |
| Horse Riding | 1 | No, minimum |
Final result:
| activity |
|---|
| Singing |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each row in Friends is processed once during grouping |
| Space | O(n) | The grouped aggregation stores counts for activities |
The dominant operation is the GROUP BY aggregation over the Friends table. After aggregation, computing maximum and minimum values is linear in the number of distinct activities. Since each activity is processed a constant number of times, the total complexity remains linear.
Test Cases
# Example case
counts = {
"Eating": 3,
"Singing": 2,
"Horse Riding": 1
}
assert [
activity
for activity, cnt in counts.items()
if cnt not in (max(counts.values()), min(counts.values()))
] == ["Singing"] # standard example
# All activities have same count
counts = {
"A": 2,
"B": 2,
"C": 2
}
assert [
activity
for activity, cnt in counts.items()
if cnt not in (max(counts.values()), min(counts.values()))
] == [] # everything excluded
# Multiple maximum activities
counts = {
"A": 5,
"B": 5,
"C": 3,
"D": 1
}
assert [
activity
for activity, cnt in counts.items()
if cnt not in (max(counts.values()), min(counts.values()))
] == ["C"] # both maximum activities removed
# Multiple minimum activities
counts = {
"A": 4,
"B": 2,
"C": 2,
"D": 5
}
assert set(
activity
for activity, cnt in counts.items()
if cnt not in (max(counts.values()), min(counts.values()))
) == {"A"} # both minimum activities removed
# Only two activities
counts = {
"A": 10,
"B": 1
}
assert [
activity
for activity, cnt in counts.items()
if cnt not in (max(counts.values()), min(counts.values()))
] == [] # no middle activity
# Larger mixed case
counts = {
"A": 7,
"B": 3,
"C": 5,
"D": 1,
"E": 6
}
assert set(
activity
for activity, cnt in counts.items()
if cnt not in (max(counts.values()), min(counts.values()))
) == {"B", "C", "E"} # several valid middle activities
| Test | Why |
|---|---|
| Standard sample case | Verifies normal functionality |
| All equal counts | Ensures empty result when min equals max |
| Multiple maximum activities | Confirms all maximum-count activities are excluded |
| Multiple minimum activities | Confirms all minimum-count activities are excluded |
| Only two activities | Ensures no middle activity exists |
| Larger mixed dataset | Validates filtering with several intermediate counts |
Edge Cases
One important edge case occurs when all activities have exactly the same number of participants. In this scenario, the minimum and maximum counts are identical. Since every activity matches both values simultaneously, all activities must be excluded. A careless implementation might incorrectly return every activity if it only checks one condition.
Another important case is when multiple activities share the maximum or minimum count. For example, two activities may both have five participants, while two others both have one participant. The solution must exclude all activities tied at the extremes, not just one of them. Using NOT IN against the computed maximum and minimum values naturally handles this situation.
A third edge case occurs when there are only two distinct participation counts. For example, activities may have counts {1, 1, 5, 5}. In this case, every activity is either minimum or maximum, so the result is empty. The filtering condition correctly removes all rows.
A final subtle case is ensuring that every activity exists in the Friends table. The problem guarantees this property, so we do not need outer joins or null handling. Without this guarantee, activities with zero participants would require special handling.