Problem 1604

Abstract / Summary

Track key-card uses and alert if the same card is used three or more times within any one hour.

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 1604.py

class Solution:
    def alertNames(self, keyName: List[str], keyTime: List[str]) -> List[str]:
        # one hour alert, measured in minutes
        threshold = 60

        # split into names
        all = defaultdict(list)
        for n, t in zip(keyName, keyTime):
            # convert HH:MM to minutes since midnight
            a, b = t.split(":")
            minutes = int(a) * 60 + int(b)
            all[n].append(minutes)

        # and sort
        for user in sorted(all):
            one = two = -inf
            for three in sorted(all[user]):
                if three - one <= 60:
                    yield user
                    break

                one = two
                two = three
23 lines | 730 bytes | submitted December 8, 2023 | GitHub   25% comment ratio | tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 46% (100k+ submissions).

Typical patterns to solve this problem:
  • Array
  • Hash Table
  • Sorting
  • String
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The provided Solution class implements a method that identifies employee names who used a key card three or more times within any one-hour window. The method receives two parallel lists: keyName, containing employee identifiers, and keyTime, containing timestamps in "HH:MM" format. It returns a list of distinct employee names that meet the alert condition, sorted alphabetically.

Data Preparation

The first logical block groups timestamps by employee name.

all = defaultdict(list)
for n, t in zip(keyName, keyTime):
    a, b = t.split(":")
    minutes = int(a) * 60 + int(b)
    all[n].append(minutes)

Each timestamp string is split at the colon, converting hours and minutes into a single integer representing minutes since midnight. The resulting integer is appended to a list associated with the employee’s name in a defaultdict. This conversion simplifies subsequent arithmetic comparisons.

Sorting for Deterministic Traversal

Before scanning for alerts, the code sorts the employee keys and the individual timestamp lists.

for user in sorted(all):
    for three in sorted(all[user]):
        ...

Sorting the keys ensures that the final output respects alphabetical order without an extra sorting step at the end. Sorting each user’s timestamps guarantees that the sliding-window check proceeds chronologically, which is essential for correctly detecting a one-hour interval.

Sliding-Window Detection

The core detection logic maintains three variables that represent the most recent three timestamps encountered for a given user.

one = two = -inf
for three in sorted(all[user]):
    if three - one <= 60:
        yield user
        break
    one = two
    two = three

Initially, one and two are set to negative infinity, ensuring that the first two iterations cannot falsely trigger the alert condition. As the loop iterates over sorted timestamps, the difference between the current timestamp (three) and the timestamp three positions earlier (one) is evaluated. If this difference does not exceed the 60-minute threshold, the user satisfies the alert criterion, and the generator yields the user’s name, terminating further checks for that user.

Edge-Case Handling

The conversion of "HH:MM" to minutes correctly handles times at the start of the day ("00:00") and at the end of the day ("23:59"), because the arithmetic is based on a 24-hour clock expressed in total minutes. The use of -inf for the initial placeholders prevents accidental matches when fewer than three timestamps exist for a user; the condition three - one <= 60 can never be true until three genuine timestamps have been processed. Additionally, the early break after yielding a user ensures that users with many qualifying windows are reported only once, avoiding duplicate entries.

Performance Optimizations

Grouping timestamps with a defaultdict avoids repeated existence checks and list initializations, providing constant-time insertion per record. Converting timestamps to integer minutes up front eliminates repeated string parsing during the sliding-window scan, reducing overhead. Sorting each user’s timestamp list once enables a linear pass with a fixed-size sliding window, avoiding nested loops that would otherwise increase work. The early exit (break) after detecting an alert for a user prevents unnecessary iteration over the remainder of that user’s timestamps, saving cycles when the condition is met early in the list.

Output Generation

The method uses a generator (yield) inside the loop, allowing the caller to collect results lazily. When the generator is consumed (e.g., via list(solution.alertNames(...))), the yielded names are already in alphabetical order because the outer loop iterates over sorted(all). This design eliminates the need for a separate sorting step on the final result set.

written by openai gpt

ELI5 - Simplified Explanation

Imagine a big notebook that tracks when people use their access badges to enter a room. The code starts by reading through all the entries in the notebook. It takes the names of the people and the times they entered, like ten fifteen, and translates those times into just the number of minutes that have passed since the day began. This makes it much easier to compare the times later on.

All the entry times for each person are put together into little lists. Once the lists are ready, the code looks at each person one by one to see how they used their badge. To make sure the check is fair, the code keeps the entry times in order from the beginning of the day to the end.

As it goes through the times for a single person, it keeps track of the three most recent times used to enter the room. If it notices that the person entered the room three times within a single hour, it marks them down for an alert. It does this by checking if the time of the third entry is close enough to the time of the first entry in that set. If everything matches up, the person gets an alert for using their badge too many times in a row.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 26 | median = 5 | μ = 5.00 | σ = 1.96

Complexity Analysis

Time: loglinear
As a rule of thumb, the maximum input size for one second execution time is
  • factorial: up to 10 elements
  • exponential: up to 20 elements
  • polynomial: a few thousand elements
  • loglinear: up to 100,000 elements
  • linear: a few million elements
  • logarithmic: a billion elements
  • constant: practically unlimited
generated automatically

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java Go TS
Progiez C++ Python Java
github black-shadows C++
charles-wangkai Java
fsq C++
JoshCrozier JS
keineahnung2345 C++
lkwq007 Python
suxrobGM C#
trung-hn Python
varunu28 Java
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, Go, Java, Python, TypeScript
Progiez C++, Java, Python
black-shadows C++, C++
charles-wangkai Java
fsq C++
JoshCrozier JavaScript
keineahnung2345 C++
lkwq007 Python
suxrobGM C#
trung-hn Python
varunu28 Java
24 links | 13 authors | 7 languages

Videos

4 videos   did my crawler come up with invalid videos ? drop me a line.

Solved On The Same Day

10 solutions   December 8, 2023

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality