题目意思很直接:给你一条日志消息 message 和当前时间戳 timestamp,同一条消息 10 秒内只能打印一次。如果能打印,返回 true,否则返回 false。
刚看到这题,很多人会先想队列、滑动窗口,甚至想整一套清理机制。其实这题核心没那么绕,真正要记的只有一件事:同一条 message 上一次被打印的时间是多少。
那最顺手的做法就是 HashMap<String, Integer>。
import java.util.HashMap;import java.util.Map;classLogger{privatefinal Map<String, Integer> lastPrintTime = new HashMap<>();publicbooleanshouldPrintMessage(int timestamp, String message){ Integer lastTime = lastPrintTime.get(message);if (lastTime == null || timestamp - lastTime >= 10) { lastPrintTime.put(message, timestamp);returntrue; }returnfalse; }}
这段代码不长,但已经够用了。
比如:
Logger logger = new Logger();System.out.println(logger.shouldPrintMessage(1, "order timeout")); // trueSystem.out.println(logger.shouldPrintMessage(2, "order timeout")); // falseSystem.out.println(logger.shouldPrintMessage(11, "order timeout")); // true
这里要注意一个小点:题目限制的是“10 秒内不能重复打印”,所以判断条件要写成 timestamp - lastTime >= 10。 这个边界很容易手滑写错成 > 10,结果第 11 秒能过,第 10 秒反而过不了。
再看下这个解法为什么合适。
message 是 key,最近一次打印时间是 value。每来一次请求,只做一次 get 和一次可能的 put,平均时间复杂度是 O(1)。这就很像线上接口做幂等限流时,Redis 里存一个最近访问时间戳,思路本质上是一样的,只不过这题在内存里做。
当然,这个实现有个很现实的问题: 如果日志种类特别多,HashMap 会一直涨,不会自动清理。
在算法题语境里这不是重点,直接过题没问题。但如果你把它往工程里搬,通常会补一个过期淘汰。比如可以定时扫描,也可以直接换成带 TTL 的缓存。
像这样:
// 伪代码,表达思路if (cache.contains(message) && now - cache.get(message) < 10) {returnfalse;}cache.put(message, now); // 10秒后过期returntrue;
所以这题本身不复杂,难点不在数据结构有多花,而是在你能不能把约束收干净:限制的是同一条消息,不是全局日志;卡的是最近 10 秒,不是打印次数。
面试里这种题,先把最小正确解写出来,往往比一上来堆复杂设计更稳。 先用 HashMap 把“最后一次出现时间”记住,这题基本就结束了。