Quick Overview

Given unordered login records of user ids and calendar dates, return the longest run of consecutive days on which a single user logged in, counting repeat logins on the same day once. Tests grouping by user, date arithmetic across month, year and leap-day boundaries, and counting runs that reset after a gap.

Longest Streak of Consecutive Login Days by a Single User

Company: Amazon

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Technical Screen

You are given login records, each a user id and the calendar date of one login. Return the length of the longest streak of consecutive days on which a single user logged in. A streak ends as soon as that user's next login date is more than one day after the previous one; counting then starts again. The candidate's report does not say whether the answer is reported per user or overall; this version returns the longest streak achieved by any single user. ### Function Signature ```python def longest_login_streak(logins: list[list[str]]) -> int: ``` ### Rules - Each record is `[user_id, date]`, where `date` is a valid Gregorian calendar date in `YYYY-MM-DD` format. - Records are in no particular order, and a user may log in several times on the same day; those logins count as one day. - A streak is a maximal run of consecutive calendar days on each of which one user logged in at least once. Consecutive days cross month and year boundaries normally, and February 29 is a real day in leap years. - A streak belongs to one user: logins by other users never extend or break it. - Return the length, in days, of the longest streak over all users. ### Constraints - `1 <= len(logins) <= 10^5` - `user_id` has 1 to 20 characters, each a lowercase English letter or a digit. - Every date lies between `2000-01-01` and `2099-12-31`. ### Examples **Example 1** ```text Input: logins = [["u1", "2026-05-03"], ["u2", "2026-05-03"], ["u1", "2026-05-04"], ["u1", "2026-05-04"], ["u1", "2026-05-06"], ["u2", "2026-05-04"], ["u2", "2026-05-05"]] Output: 3 ``` User `u1` logged in on May 3, May 4 (twice) and May 6, giving streaks of 2 and 1 days. User `u2` logged in on May 3, 4 and 5, a streak of 3 days. **Example 2** ```text Input: logins = [["a", "2024-03-01"], ["a", "2024-02-28"], ["a", "2024-02-29"], ["b", "2024-03-02"]] Output: 3 ``` User `a` logged in on February 28, February 29 (2024 is a leap year) and March 1, a streak of 3 days. User `b`'s login on March 2 does not extend `a`'s streak. **Example 3** ```text Input: logins = [["z", "2025-12-31"], ["z", "2026-01-02"]] Output: 1 ``` January 1 is missing, so the two logins form two separate streaks of 1 day.

Overview: Given unordered login records of user ids and calendar dates, return the longest run of consecutive days on which a single user logged in, counting repeat logins on the same day once. Tests grouping by user, date arithmetic across month, year and leap-day boundaries, and counting runs that reset after a gap.

Read the full Amazon Software Engineer interview experience this question came from

You are given a list of login records `logins`. Each record is `[user_id, date]`: the id of a user and the calendar date of one of that user's logins, written as a valid Gregorian date in `YYYY-MM-DD` format. A **streak** is a maximal run of consecutive calendar days on each of which one user logged in at least once. A streak ends as soon as that user's next login date is more than one day after the previous one; counting then starts again. Return the length, in days, of the longest streak achieved by any single user. Rules: - Records are in no particular order. - A user may log in several times on the same day; those logins count as one day. - Consecutive days cross month and year boundaries normally (for example, `2023-12-31` is followed by `2024-01-01`), and February 29 is a real day in leap years. - A streak belongs to one user: logins by other users never extend or break it. The answer is always between 1 and 36,525 (the number of days from `2000-01-01` through `2099-12-31`), so it never exceeds 2^31 - 1 and fits in a 32-bit signed integer. **Example 1** ```text Input: logins = [["u1", "2026-05-03"], ["u2", "2026-05-03"], ["u1", "2026-05-04"], ["u1", "2026-05-04"], ["u1", "2026-05-06"], ["u2", "2026-05-04"], ["u2", "2026-05-05"]] Output: 3 ``` User `u1` logged in on May 3, May 4 (twice) and May 6, giving streaks of 2 and 1 days. User `u2` logged in on May 3, 4 and 5, a streak of 3 days. **Example 2** ```text Input: logins = [["a", "2024-03-01"], ["a", "2024-02-28"], ["a", "2024-02-29"], ["b", "2024-03-02"]] Output: 3 ``` User `a` logged in on February 28, February 29 (2024 is a leap year) and March 1, a streak of 3 days. User `b`'s login on March 2 does not extend `a`'s streak. **Constraints** - `1 <= len(logins) <= 10^5` - Each `logins[i]` is a two-element list `[user_id, date]`. - `user_id` has 1 to 20 characters, each a lowercase English letter or a digit. - `date` is a valid Gregorian calendar date in `YYYY-MM-DD` format. - Every date lies between `2000-01-01` and `2099-12-31` inclusive. - Records may appear in any order, and the same `[user_id, date]` pair may appear more than once.

Constraints

  • 1 <= len(logins) <= 10^5
  • Each logins[i] is a two-element list [user_id, date].
  • user_id has 1 to 20 characters, each a lowercase English letter or a digit.
  • date is a valid Gregorian calendar date in YYYY-MM-DD format.
  • Every date lies between 2000-01-01 and 2099-12-31 inclusive.
  • Records may appear in any order, and the same [user_id, date] pair may appear more than once.

Examples

Input: ([['u1', '2026-05-03'], ['u2', '2026-05-03'], ['u1', '2026-05-04'], ['u1', '2026-05-04'], ['u1', '2026-05-06'], ['u2', '2026-05-04'], ['u2', '2026-05-05']],)

Expected Output: 3

Explanation: Source example 1: u1 has streaks of 2 and 1 (the repeated May 4 login counts once); u2 logs in May 3-5 for 3.

Input: ([['a', '2024-03-01'], ['a', '2024-02-28'], ['a', '2024-02-29'], ['b', '2024-03-02']],)

Expected Output: 3

Explanation: Source example 2: a covers 2024-02-28, 02-29 and 03-01 (leap year) for 3; b's March 2 login does not extend a's streak.

Hints

  1. A streak never mixes users, so think about each user's logins on their own.
  2. Several logins by one user on the same day still count as a single day of a streak.
  3. Check that your test for 'the next calendar day' works at the end of a 30-day month, on December 31, and around February 29 in both leap and non-leap years.

Loading coding console...

Show the approach

Approach

Algorithm: group the records by user_id and turn every date into an absolute day number, so that two dates are consecutive calendar days exactly when their numbers differ by 1. The conversion treats March as the first month of a shifted year (so February, with its optional 29th day, is the last month), counts 365 days per shifted year plus the leap days given by year/4 - year/100 + year/400, and adds the cumulative days of the earlier shifted months, (153 * month_index + 2) / 5. This handles 30- and 31-day month ends, December 31 to January 1, February 29 in leap years (including 2000, divisible by 400) and February 28 to March 1 in non-leap years without special cases. For each user, sort the day numbers and scan them once: a value equal to the previous one is a repeat login on the same day and is skipped, a value exactly one more than the previous one extends the current run, and any larger jump starts a new run of length 1. The answer is the largest run seen across all users.

Invariant: while scanning one user's sorted day numbers, run equals the length of the longest sequence of consecutive distinct days that ends at the current distinct day, and best is the maximum run over everything scanned so far.

Correctness: a streak is a maximal block of distinct days d, d+1, ..., d+k-1 for one user. After sorting and removing repeats, such a block appears as adjacent entries that each differ by 1, and it is bounded by gaps larger than 1 (or by the ends of the list), so the scan's run reaches exactly k at its last day and resets at the next gap. Every user's streaks are therefore measured exactly once, and the maximum over users is returned.

Edge cases: a single record gives 1; a list of identical records gives 1 because repeats never extend a run; logins by other users live in other groups, so they can neither fill a gap nor interrupt a streak; input order does not matter because each user's days are sorted; dates from 2000-01-01 through 2099-12-31 give day numbers well inside 32-bit range, and the answer is at most 36,525.

Time complexity:
O(n log n)
Space complexity:
O(n)