Google 面试题:Robot Status Message 去重,10 秒窗口内重复消息不展示

这次分享一道 Google 面试中出现的 coding 题,题目本身不算特别长,但很考察候选人对细节的理解能力,尤其是“过去 10 秒内已经展示过”的边界判断。如果面试时一紧张,很容易把它写成简单的 Set 去重,或者误以为只要消息出现过就永远不再展示。

题目大意是这样的:

有一个 robot 会不断发送 status messages,这些消息会被人类实时读取。由于短时间内可能产生大量重复消息,直接展示会很难读。现在希望实现一个程序:如果某条 message 在过去 10 秒内已经被展示过,那么这次就隐藏;如果超过 10 秒没有展示过,就可以再次展示。

题目给了一个例子:

10 solar panel activated
11 low battery warning
12 tire one: low air pressure
13 solar panel activated
14 low battery warning
21 solar panel activated
35 solar panel activated

最终展示给用户的是:

10 solar panel activated
11 low battery warning
12 tire one: low air pressure
21 solar panel activated
35 solar panel activated

这里的关键点在于,13 秒的 solar panel activated 不能展示,因为 10 秒已经展示过同样消息;14 秒的 low battery warning 也不能展示,因为 11 秒刚展示过。到了 21 秒,距离 10 秒那次展示已经超过 10 秒,所以可以重新展示。35 秒同理,也可以展示。

这道题表面看像“去重”,但真正要实现的是一个 time-window based duplicate suppression。候选人需要维护每条消息最近一次“被展示”的时间,而不是最近一次“被接收”的时间。

比如 solar panel activated 在 13 秒收到时被隐藏了,那么它不应该更新 last shown time。因为用户并没有在 13 秒看到这条消息。如果错误地更新成 13,那么 21 秒时就会误判为 8 秒内重复,从而错误隐藏。

所以正确逻辑应该是:

如果 message 从未展示过:
展示,并记录当前时间

如果 message 展示过:
判断当前时间 - lastShownTime 是否超过 10 秒
如果超过或等于题目定义允许的边界:
展示,并更新 lastShownTime
否则:
隐藏,不更新 lastShownTime

面试中比较容易被追问的是边界条件。比如 timestamp = 10 展示过,timestamp = 20 再次收到同样消息,到底能不能展示?题目说 “within the past 10 seconds”,通常可以理解为过去 10 秒窗口内重复则隐藏,刚好相隔 10 秒是否允许,需要和面试官确认。实际面试里,候选人应该主动问一句:

“Should a duplicate at exactly 10 seconds later be shown or hidden?”

如果面试官说 10 秒以内隐藏,满 10 秒可以展示,那么条件就是:

currentTime - lastShownTime >= 10

如果面试官说过去 10 秒包含边界,那么条件就是:

currentTime - lastShownTime > 10

这类 clarification 在 Google 面试里很重要,因为它不是单纯写代码,而是在展示你如何定义产品规则和处理 ambiguity。

实现上,如果输入消息是按时间递增到来的,最简单的做法是用一个 HashMap:

Map<String, Integer> lastShownTime

key 是 message 内容,value 是这条 message 最近一次真正展示给用户的 timestamp。

每次收到新消息时:

if message 不在 map 中:
show
map[message] = timestamp

else:
if timestamp - map[message] >= 10:
show
map[message] = timestamp
else:
hide

时间复杂度是 O(n),每条消息只处理一次。空间复杂度是 O(m),m 是不同 message 的数量。

如果进一步追问系统长期运行怎么办,HashMap 会不会越来越大,这时就需要讲 cleanup。因为 robot 可能运行很久,历史消息非常多,不能无限存所有 message。可以用 queue 维护最近展示过的记录:

Queue<(timestamp, message)>
Map<message, lastShownTime>

每次处理新消息前,把 queue 里已经超过窗口很久的记录清理掉。但清理时要注意,queue 里可能有旧记录,而 map 里保存的是更新后的 lastShownTime,所以删除 map 之前必须确认:

if map[message] == oldTimestamp:
remove message from map

这样可以避免误删后来又展示过的消息。

这道题的难点不在代码量,而在这几个细节:

第一,判断依据是“最近一次展示时间”,不是“最近一次接收时间”。

第二,被隐藏的重复消息不能更新 lastShownTime。

第三,10 秒边界需要主动和面试官确认。

第四,如果扩展成长期运行的 real-time service,需要考虑内存清理。

在我们的面试辅助过程中,这类题通常不会直接让候选人上来就写代码。我们会先帮候选人把题目拆成可沟通的几个部分:输入输出是什么、窗口规则是什么、边界如何定义、数据结构为什么选 HashMap、follow-up 如何处理长期运行的内存问题。这样候选人在面试里说出来的不是“我会写一个 map”,而是一个完整、自然、像真实工程师一样的解题过程。

csoahelp 做的就是这种场景里的实时辅助,题目刚读完就能给出完整思路,现场不用卡壳。

我们也有代面试,面试辅助,OA代写等服务助您早日上岸~

Leave a Reply

Your email address will not be published. Required fields are marked *