Alert Using Same Key-Card Three or More Times: Hash Map Grouping with Sliding Window
Alert Using Same Key-Card Three or More Times in a One Hour Period (LeetCode 1604) is a clean example of combining two fundamental patterns: hash map grouping and sorting with a sliding window. If you have solved Group Anagrams, you already know half the solution. The other half is a simple time comparison.
The problem
You are given two arrays of equal length: keyName and keyTime. Each keyName[i] is the name of an employee and keyTime[i] is the time they used a key-card, formatted as "HH:MM" in 24-hour format. An employee triggers an alert if they use the key-card three or more times within a one-hour window (inclusive).
Return a list of the names of employees who triggered an alert, sorted in alphabetical order.
Example:
keyName = ["daniel","rafael","daniel","daniel","clare","clare","clare","clare","rafael"]
keyTime = ["10:00","12:00","10:40","11:00","09:00","09:20","09:30","10:00","13:00"]
Output: ["clare","daniel"]
Both clare and daniel have three or more swipes that fall within a one-hour window. rafael only swiped twice, so no alert.
Why this problem matters
This problem tests your ability to break a messy, real-world scenario into two clean sub-problems. The input arrives as unsorted, interleaved data from multiple employees. You need to organize it, then analyze it. That "organize then analyze" pattern shows up constantly in interview problems and production code alike.
The key insight
The trick is to split this into two phases:
- Group all swipe times by employee name (hash map)
- Sort each employee's times and check if any window of three consecutive swipes spans 60 minutes or less
The grouping step is identical to Group Anagrams. You iterate through the input, build a defaultdict(list), and bucket each time under its employee name. The checking step is a small sliding window: for each sorted list of times, compare times[i+2] - times[i] for every valid i. If the difference is <= 60 minutes, that employee triggers an alert.
Why three consecutive? If any three swipes fall within one hour, then after sorting, at least three consecutive swipes must also fall within that window. Sorting guarantees this.
The solution
from collections import defaultdict
def alertNames(keyName: list[str], keyTime: list[str]) -> list[str]:
swipes = defaultdict(list)
for name, time in zip(keyName, keyTime):
h, m = time.split(":")
swipes[name].append(int(h) * 60 + int(m))
result = []
for name, times in swipes.items():
times.sort()
for i in range(len(times) - 2):
if times[i + 2] - times[i] <= 60:
result.append(name)
break
result.sort()
return result
Here is what each part does:
swipes = defaultdict(list)creates the hash map for grouping. Each name maps to a list of swipe times.int(h) * 60 + int(m)converts"HH:MM"into total minutes since midnight. This makes time comparisons simple subtraction instead of messy string parsing.times.sort()sorts each employee's swipe times in ascending order. This is what enables the sliding window.- The inner loop checks every window of three consecutive swipes. If
times[i + 2] - times[i]is at most 60, we found three swipes within one hour. We add the name andbreakout early since we only need to flag the employee once. result.sort()returns the names in alphabetical order as required.
Converting times to minutes early simplifies everything. Instead of parsing hours and minutes during comparison, you work with plain integers. The conversion int(h) * 60 + int(m) turns "09:30" into 570 and "10:00" into 600. The difference is 30 minutes, just basic subtraction.
Visual walkthrough
Let's trace through the full example step by step. Watch how grouping, sorting, and the sliding window work together.
Step 1: Group swipe times by employee name using a hash map.
Each name maps to a list of all their swipe times. This is the group-by-key pattern.
Step 2: Sort each employee's swipe times in ascending order.
Sorting lets us use a sliding window. If swipes are out of order, we cannot check consecutive windows correctly.
Step 3: Check daniel's times. Window [10:00, 10:40, 11:00]. 11:00 - 10:00 = 60 min.
Three swipes within 60 minutes. 60 is within one hour (using <= 60). daniel triggers an alert.
Step 4: Check rafael's times. Only 2 swipes total. Cannot have 3 in any window.
rafael has fewer than 3 swipes. No window check needed. No alert.
Step 5: Check clare's times. Slide a window of size 3 across sorted times.
Window [09:00, 09:20, 09:30]: 09:30 - 09:00 = 30 min. Three swipes within one hour. clare triggers an alert.
After checking all employees, we collect the flagged names and sort them alphabetically: ["clare", "daniel"].
Complexity analysis
| Metric | Value | Explanation |
|---|---|---|
| Time | O(n log n) | Grouping is O(n). Sorting each group is O(n log n) in the worst case (one employee with all swipes). The window checks are O(n) total. |
| Space | O(n) | The hash map stores all n swipe times. The result list is at most the number of distinct employees. |
The dominant cost is sorting. If the number of distinct employees is large and each has few swipes, the sorting cost is closer to O(n log(n/k)) where k is the number of employees, but O(n log n) is the safe upper bound.
The building blocks
This problem combines two sub-patterns that you will see again and again.
Group-by-key (hash map grouping)
Iterate through a collection, compute a key for each element, and bucket elements that share the same key. The template is always the same:
from collections import defaultdict
groups = defaultdict(list)
for item in collection:
key = compute_key(item)
groups[key].append(item)
In this problem, compute_key is just the employee name. In Group Anagrams, it is the sorted characters. In frequency counting problems like Top K Frequent Elements, it is the element itself. The pattern never changes, only the key function does.
Sliding window on sorted data
After sorting, check whether any window of k consecutive elements satisfies a condition. The general template:
data.sort()
for i in range(len(data) - k + 1):
if data[i + k - 1] - data[i] <= threshold:
return True
Here, k = 3 and threshold = 60. This is simpler than the general sliding window pattern because the window size is fixed. You do not need to expand and contract. You just slide a fixed-size window across the sorted array.
Edge cases
A few scenarios to consider:
- Fewer than 3 swipes for an employee. If someone only swiped once or twice, they cannot trigger an alert. The inner loop simply will not execute because
range(len(times) - 2)produces an empty range. - Exactly 3 swipes spanning exactly 60 minutes. The problem says "within a one-hour period" which is inclusive.
times[i + 2] - times[i] <= 60handles this correctly. - All swipes at the same time. Multiple swipes at
"00:00"for the same person. The difference is 0, which is<= 60. Alert triggered correctly. - Times crossing midnight. The problem guarantees times are in
"HH:MM"24-hour format within a single day. There is no midnight wraparound to worry about. - Single employee with many swipes. The algorithm handles this efficiently. Sort once, scan once with the sliding window.
From understanding to recall
The insight here is not complicated: group by name, sort, check windows. But under interview pressure, you might waste time figuring out the right window size, or forget to convert times to minutes, or try to handle the grouping and checking in a single tangled loop.
Spaced repetition helps you internalize the two-phase structure: group first, then analyze. Once you have typed this pattern a few times at increasing intervals, the decomposition becomes automatic. You see a problem with interleaved data from multiple entities, and you immediately think "group by key, then process each group." The grouping template fires without hesitation. The analysis step is the only part that varies.
Related posts
- Group Anagrams - The canonical group-by-key problem. Same hash map grouping pattern, different analysis step.
- Top K Frequent Elements - Another hash map problem that groups by key and then processes each group with a second pass.
- Hash Map Patterns - The three core hash map techniques, including the grouping pattern used in this problem.
Once you have the grouping pattern down and understand the fixed-size sliding window, problems like this one become a matter of assembly rather than invention. You pick up the right bricks and put them together.