微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在给定的时间范围内有效地统计独立事件 问题描述我的解决方案

如何解决在给定的时间范围内有效地统计独立事件 问题描述我的解决方案

问题描述

我几次遇到这个问题,并且一直想知道我的解决方案是否是最优的,或者(更有可能)有更好的解决方案。

说我的组件接收事件,该事件由时间和字符串组成。对于我收到的每个事件,我需要返回在过去x秒内看到了多少个独立的字符串。 (x是可配置的,但在执行开始时已固定)。 “最后x秒”是指时间范围,该时间段在事件发生时以最高的时间戳记结束,并且持续x秒(包括两端)。

让我举个例子。我以给定的顺序收到以下事件(由(time,string)表示),并且对于每个事件,假设x = 5,我都会显示预期的返回值。

  • (1,“ a”)→1
  • (2,“ b”)→2
  • (3,“ a”)→2
  • (7,“ c”)→3
  • (9,“ c”)→1
  • (8,“ d”)→2

我们不能假设事件以正确的顺序出现,但是我们可以假设差异很小,即,如果将事件放在有序列表中,则在大多数情况下,您会在事件末尾添加事件列表或非常接近列表。

此外,字符串在这里一个简化。它们实际上是可以比较相等性并计算其哈希值的对象,但不能对其进行排序或处理。 (不过,在其余的问题中,我将这些对象称为“字符串”。)


我的解决方

我将使用两种数据结构:双端队列和哈希映射。前者包含按时间顺序排列的事件,后者包含在最近x秒内看到的字符串以及显示它们已被查看多少次的计数器。

对于收到的每个事件,我都将其添加到队列中并增加地图中的计数器。然后,我将移至队列的开头,并从中删除所有时间戳过旧(即,低于time_of_last_event - x)的事件;对于每个删除的事件,我将减少映射中的相应计数器,如果其计数器为零,则将其从映射中删除。最后,地图的大小是我必须返回的数字。

如果乱序事件经常发生,但是事件是“几乎乱序”的,我可以考虑使用双链表而不是双头队列;当插入事件时,我将从其末尾开始搜索,以找到适合该事件插入的位置。这将使我免于过多的重新分配,但是我不确定为我插入的每个事件分配内存都会在性能方面有所回报。

假设在队列末尾插入了固定时间,从其开始处进行了恒定时间删除,并且在哈希映射中进行了恒定时间操作,我想说的是,每次调用此算法都将摊销恒定时间(长运行时,我将删除插入的条目,因此每次调用平均删除一个条目。


主要问题是:是否有比所描述的算法更好的算法? 更好的是,我的意思是说算法可以运行得更快或使用更少的内存。

还有几个问题

  • 此算法有什么问题吗?
  • 这是一个众所周知的问题吗?有名字吗?我什么也找不到,但是可能搜索错误的关键字。

解决方法

如果您按顺序接收事件,则您的解决方案足够有效,但是,如果没有按顺序接收事件,该算法将变成二次函数,因为在双链表中将新元素插入到已排序位置的工作将需要线性时间(根据列表的大小)。如果将 x 视为常数,则可能不会出现问题,因为总时间复杂度仍然为 O(n)。但是,如果您将 x 视为变量,那么这不是最佳选择。

解决方案是使用最小堆而不是队列或双向链表:

插入每个新元素,以时间戳为键。当堆的大小大于 x 的大小时,请删除堆的根,因为它代表的是与堆中其他 x 项相比最旧的条目

对于其他情况,您可以像往常一样继续进行哈希映射。

由于从堆中插入和移除具有 O(logx)时间复杂度,所以总时间复杂度为 O(nlogx)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。