Problemwebsite retention tracker

Session: Sign in to solve

Solution.txt

Website Retention Tracker

Problem

Design WebsiteRetentionTracker to record the distinct users who visit a website on each calendar date and calculate adjacent-day retention. Multiple threads may call one shared tracker instance.

Requirements

  • Distinct daily visitors. recordVisit adds the user to the supplied date's visitor cohort. Repeating the same user and date has no additional effect.
  • Adjacent-day retention. If the immediately previous calendar date has visitors, calculateRetentionRate(date) returns the number of those visitors who also visited on date, divided by the number of distinct previous-day visitors.
  • Empty previous day. If no visitors were recorded for the immediately previous calendar date, calculateRetentionRate returns 0.0.
  • Valid inputs. A user ID must be from 1 through 2147483647. A date must be a zero-padded YYYY-MM-DD string naming a valid proleptic Gregorian date from 0001-01-01 through 9999-12-31.
  • Shared access. Calls on one shared instance are linearizable.

API

SignatureReturnsBehavior
WebsiteRetentionTracker()Not applicableCreates an empty tracker.
recordVisit(userId: integer, date: string)voidRecords one visit. Invalid input raises InvalidArgumentError without changing any cohort.
calculateRetentionRate(date: string)numberCalculates retention for date. An invalid date or 0001-01-01 raises InvalidArgumentError.

Examples

StepOperationResult
1recordVisit(3, "2026-07-29")void
2recordVisit(5, "2026-07-29")void
3recordVisit(2, "2026-07-29")void
4recordVisit(7, "2026-07-29")void
5recordVisit(4, "2026-07-30")void
6recordVisit(7, "2026-07-30")void
7recordVisit(9, "2026-07-30")void
8calculateRetentionRate("2026-07-30")0.25

Constraints

  • At most 100000 distinct dates, 1000000 recorded visits, and 200000 public calls occur per testcase.
  • At most 100000 distinct visitors occur on one date.
  • Visitor counts fit in a signed 64-bit integer.
  • Retention results are finite values from 0.0 through 1.0.

Notes

Both methods may run concurrently. Linearizable means that each call takes effect at one instant between its invocation and return. A query observes both adjacent cohorts at the same such instant, so completed recordings are not lost and the result matches one legal ordering of overlapping calls. Calls within one thread retain program order; calls across threads may use any ordering with that property. Neither method waits for future visits or external events, and finite lock contention is allowed, but calls must not deadlock.

PRIVATE WORKSPACE

Checking your session…

The statement is public. The editor, editorial, submissions, and saved work are private.