0Pricing
Coding Interview Prep · 课时

截至今天的当前连续记录

计算正在持续的连续记录,并在中断时重置。

截至今天的当前连续记录 是 CoddyKit 上的免费 Coding Interview Prep 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Coding Interview Prep 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Coding Interview Prep 课程共包含 4 节课。

产品问题

连续天数功能(例如 Duolingo 或 Snapchat)需要的是当前连续天数,而不是历史最长连续天数。面试题可能这样问:“对于每位用户,截至今天,他们连续活跃了多少天?如果今天没有活跃,则重置为 0。”

这带来了一个变化:连续天数必须锚定在今天(或者根据宽限规则锚定在昨天)。让我们基于您已经掌握的间隔与连续区段基础来构建它。

定义活跃状态

首先与面试官明确规则 — 这些决定会改变查询:

  • 连续天数是否要求今天有活动,还是允许昨天有活动(宽限期)?
  • 每天的多个事件是否合并为一天?
  • 哪个时区定义“一天”?

我们假设每个活跃日只有一行,并且连续天数包含今天 OR 昨天时,就视为当前连续天数。

再次构建连续区段

复用之前的锚点:按日期为每位用户的每天记录编号,然后进行相减。每个连续段都会共享同一个锚点。当前连续天数就是最后一天为今天或昨天的连续区段的长度。

WITH numbered AS (
  SELECT user_id, login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY login_date
    ) AS rn
  FROM logins
),
islands AS (
  SELECT user_id,
    MIN(login_date) AS streak_start,
    MAX(login_date) AS streak_end,
    COUNT(*)        AS streak_len
  FROM numbered
  GROUP BY user_id, login_date - rn
)
SELECT * FROM islands;

确定最新连续区段

每位用户最近的连续区段,就是 streak_end 最大的那个连续区段。我们要检查这个结束日期是否足够近,从而将其视为仍在持续。

CURRENT_DATE 表示今天。CURRENT_DATE - 1 表示昨天。如果 streak_end 等于其中任一个日期,连续天数就是有效的。

WITH /* ...numbered, islands... */
latest AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY streak_end DESC
    ) AS rn2
  FROM islands
)
SELECT * FROM latest WHERE rn2 = 1;

应用新近性测试

现在判断最新的连续区段是否仍然活跃。如果它的结束日期是今天或昨天,当前连续天数就等于该区段的长度;否则,用户的连续天数已经中断,当前值为 0。

SELECT user_id,
  CASE
    WHEN streak_end >= CURRENT_DATE - 1
    THEN streak_len
    ELSE 0
  END AS current_streak
FROM latest
WHERE rn2 = 1;

完整的当前连续天数查询

整合所有层:编号、构建连续区段、按用户选出最新区段,然后应用新近性 CASE。这就是完整答案。

WITH numbered AS (
  SELECT user_id, login_date,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY login_date
    ) AS rn
  FROM logins
),
islands AS (
  SELECT user_id,
    MAX(login_date) AS streak_end,
    COUNT(*)        AS streak_len
  FROM numbered
  GROUP BY user_id, login_date - rn
),
latest AS (
  SELECT *,
    ROW_NUMBER() OVER (
      PARTITION BY user_id ORDER BY streak_end DESC
    ) AS rn2
  FROM islands
)
SELECT user_id,
  CASE WHEN streak_end >= CURRENT_DATE - 1
       THEN streak_len ELSE 0 END AS current_streak
FROM latest
WHERE rn2 = 1
ORDER BY user_id;

仅限今天的严格规则

如果业务规则比较严格 — 只有用户今天活跃时,连续天数才算有效 — 就将比较条件改为要求 streak_end = CURRENT_DATE。

宽限期版本(>= CURRENT_DATE - 1)更加友好,也常见于实际应用,因为当天可能还没有结束。请始终确认面试官要求哪一种规则。

CASE WHEN streak_end = CURRENT_DATE
     THEN streak_len ELSE 0 END AS current_streak

另一种方法:向后追溯

另一种有些面试官更喜欢的思路是:计算每一天与今天之间的间隔。只有当从某一天到今天的每一天都存在时,该天才属于当前连续天数。等价地,可以将 login_date 与 CURRENT_DATE - (offset from the latest) 进行比较。

连续区段方法通常更清晰,但了解另一种方法能体现您的知识深度。核心思想相同:构建一条锚定在今天的、不间断的链。

包含不活跃用户

不在 logins 中的用户没有连续区段,因此会消失。如果每位用户都必须返回连续天数(很可能是 0),请对用户列表使用 LEFT JOIN,并将结果通过 COALESCE 处理为 0。

SELECT u.user_id,
  COALESCE(s.current_streak, 0) AS current_streak
FROM users u
LEFT JOIN current_streaks s ON s.user_id = u.user_id;

时区陷阱

如果活动以时间戳存储,“今天”取决于时区。截断为日期之前,先完成时区转换。

  • 使用 UTC 存储和比较,或者先转换到用户的本地时区。
  • 在 Postgres 中使用 event_ts AT TIME ZONE 'UTC' AT TIME ZONE user_tz,然后转换为日期。
  • 直接对 UTC 时间戳使用 ::date 可能会将晚间事件归入错误的日历日期。

提到这一点可以避免一个经典的后续追问。

SELECT user_id,
  (event_ts AT TIME ZONE 'UTC'
             AT TIME ZONE 'America/New_York')::date AS local_day
FROM events;

性能与总结

对于经常刷新的仪表板,这个查询可以在一次遍历中按用户运行。为了保持响应迅速:

  • 建立 (user_id, login_date) 索引。
  • 可以选择将输入限制在最近的日期范围内 — 当前连续天数不可能包含早于其自身长度的数据,因此使用最近 400 天之类的滚动窗口通常就足够了。
  • 如果读取频率非常高,可以将每日结果物化到连续天数表中。

快速检查

确认您理解“截至现在”的锚点。

回顾

要计算截至今天的当前活跃连续天数:

  • 使用 login_date - ROW_NUMBER() 锚点构建连续区段。
  • 按照最大的 streak_end 选择每位用户的最新连续区段。
  • 只有当 streak_end 是今天(宽限时也可以是昨天)时,才返回该区段的长度,否则返回 0。
  • 对 users 使用 LEFT JOIN,以包含不活跃账户;截断为日期之前要处理好时区。

现在您已经掌握完整的连续天数分析工具集:检测连续段、最长连续天数、满足条件的 N 个连续项,以及当前连续天数。

常见问题解答

「截至今天的当前连续记录」课时是免费的吗?

是的 — 「截至今天的当前连续记录」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Coding Interview Prep 课程的其余内容,请升级到 CoddyKit PRO。 Coding Interview Prep 课程共包含 4 节课。

「截至今天的当前连续记录」这节课中我会学到什么?

计算正在持续的连续记录,并在中断时重置。 你通过在浏览器中直接运行的动手代码来练习 Coding Interview Prep,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Coding Interview Prep 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Coding Interview Prep 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「截至今天的当前连续记录」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Coding Interview Prep 课中编写并运行代码吗?

能。每节 Coding Interview Prep 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 检测连续日历日
  2. 每位用户的最长连续记录
  3. 满足条件的连续 N 行
  4. 截至今天的当前连续记录
← 返回 Coding Interview Prep