1797. 设计一个验证系统

设计验证码验证系统 — AuthenticationManager 类实现详解

验证码是验证用户身份、保护系统安全的重要手段。在很多场景下,验证码具有时效性:它们在生成后只能在一定时间内有效,过期后需要重新生成。今天我们来分析一道设计包含验证码的验证系统的算法题,并给出合理的实现方案。


题目描述

实现一个 AuthenticationManager 类,支持生成、更新(续期)、以及查询未过期验证码数目。具体要求如下:

  • 初始化时设定验证码的存活时间(timeToLive),单位为秒。
  • 生成验证码时,给定唯一标识 tokenId 和当前时间 currentTime,生成一个新的验证码,验证码在 currentTime + timeToLive 时过期。
  • 更新验证码时,给定 tokenIdcurrentTime,如果该验证码存在且未过期,则将其过期时间延长到 currentTime + timeToLive
  • 查询未过期验证码时,给定当前时间 currentTime,返回所有未过期验证码的数量。
  • 注意:如果验证码在时刻 t 过期,而某个操作恰好在时刻 t 进行,则过期判定优先于该操作,过期的验证码视为无效。

解题分析

从题目描述可知,系统需要维护每个验证码的唯一标识和其过期时间,并且能够完成以下操作:

  • 生成:添加新的 tokenId 并设置过期时间。
  • 续期:如果对应 tokenId 存在且未过期,更新其过期时间。
  • 统计:返回当前时刻所有未过期验证码数量。

这本质上是一个时间管理有效期维护问题。

主要难点:

  • 如何快速判定某个 tokenId 是否存在且未过期。
  • 如何高效统计当前未过期的验证码数目。
  • 操作之间过期判定的先后顺序。

解题方法

1. 数据结构选用

  • 使用哈希表(字典)存储 tokenId -> expireTime,可以快速根据 tokenId 查找对应过期时间。
  • 对于续期操作,先判断当前时间是否早于过期时间,只有未过期的验证码才续期。
  • 对于统计操作,遍历字典过滤出未过期的 token。

2. 具体实现

  • generate(tokenId, currentTime)
    直接在字典中添加或覆盖 tokenId,过期时间为 currentTime + timeToLive
  • renew(tokenId, currentTime)
    判断字典中是否存在 tokenId 且未过期(expireTime > currentTime),若是,则更新过期时间。
  • countUnexpiredTokens(currentTime)
    遍历字典,删除所有过期 token(expireTime <= currentTime),返回剩余 token 的数量。

3. 代码示例

class AuthenticationManager:

    def __init__(self, timeToLive: int):
        self.timeToLive = timeToLive
        self.tokens = {}  # tokenId -> expireTime

    def generate(self, tokenId: str, currentTime: int) -> None:
        self.tokens[tokenId] = currentTime + self.timeToLive

    def renew(self, tokenId: str, currentTime: int) -> None:
        if tokenId in self.tokens and self.tokens[tokenId] > currentTime:
            self.tokens[tokenId] = currentTime + self.timeToLive

    def countUnexpiredTokens(self, currentTime: int) -> int:
        # 删除过期token
        expired = [token for token, expireTime in self.tokens.items() if expireTime <= currentTime]
        for token in expired:
            del self.tokens[token]
        return len(self.tokens)

性能分析与优化

当前方案复杂度

  • generate:O(1)
  • renew:O(1)
  • countUnexpiredTokens:O(n),其中 n 是当前 token 数,因为每次调用都需要遍历字典,清理过期 token。

这种方法实现简单、代码易懂,在数据量不大时完全可用。

优化思路

如果系统中 token 数量非常多,countUnexpiredTokens 操作会变得较慢。为了优化,可以考虑:

  • 使用**优先队列(最小堆)**存储所有验证码的过期时间和 tokenId,每次操作时先从堆顶弹出过期的 token。
  • 使用字典存储当前有效的 token 及其最新过期时间,避免处理重复或已被续期的过期记录。
  • 这样可以将过期清理的复杂度降到 O(log n),提升性能。

示例说明

假设 timeToLive = 5

  1. generate("token1", 1)
    • 生成 token1,过期时间为 1 + 5 = 6。
  2. renew("token1", 2)
    • 当前时间 2,小于 6,续期,更新过期时间为 2 + 5 = 7。
  3. countUnexpiredTokens(6)
    • 当前时间 6,不包含过期时间 <= 6 的 token(token1 过期时间 7 > 6),返回 1。
  4. countUnexpiredTokens(7)
    • 当前时间 7,token1 过期时间等于 7,根据题意“过期事件优先于其他操作”,token1 视为已过期,返回 0。

总结

本文详细分析了设计验证码验证系统的需求,并给出了基于字典的简单实现方案。对于中小规模数据,该方案性能足够且易于实现。对于高性能需求,建议采用优先队列等数据结构进行优化。

通过合理设计数据结构和清理过期数据,可以实现一个高效、稳定的验证码管理系统,满足实际应用需求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值