编码:跟踪每个用户最近 N 天的记录。
Coding: Keep track of last N days of records for each user.
我正在解决一个有趣的问题,其中对于每个用户,我想保留他最后 N 天的 activity。这可以应用于许多用例,一个这样简单的用例是:
对于每个用户 - 用户可以在某一天随机来健身房 - 我想获得他在过去 90 天内去健身房的总次数。
这对我来说是一个棘手的问题。
我的想法:我想存储一个向量,其中每个条目将确定一天,然后一个布尔值可能代表他的访问。要计数,只需对数组中的该部分进行线性处理就足够了。
最好的方法是什么?
根据您需要的复杂程度,存储每次客户访问的简单数组就足够了。
每次访问时,添加一个包含 date/time 的新条目。每天,运行 检查是否有任何客户包含超过 90 天的访问记录。第一个不够旧的记录意味着没有更多的记录可以检查,所以你可以安全地移动到下一个客户端。
希望对您有所帮助!
您的想法会奏效,但它真的 space 有效吗?
你的 data-structure 会是这样的:一个布尔二维向量(你可以把它想象成一个矩阵),其中每一行是一个用户,每一列是一天(排序),所以包括:
matrix of size U x N
其中 U 是用户数。
要回答我最初提出的问题,您需要考虑这个矩阵密集的程度。如果它会很多,那么你做出了正确的选择,如果不是,那么你浪费了(很多)space。您可以在此处查看权衡。
当然,您必须考虑您的用例。在健身房的例子中,我认为这不会 space 有效,因为 most 人不是每天都去健身房(我认为),这将导致矩阵稀疏,这意味着我们浪费了 space.
另一个想法是使用单个矢量 os 大小 N
,其中对日期进行排序。每个条目都是一个链表,其中每个节点都是一个用户。
如果某个用户出现在某一天的列表中,则说明他那天去了健身房。
通过这种方法,我们根据需要精确分配了space,所以它是space最优的,不管我在矩阵案例中提到的密度如何.
然而,是这样吗?不,当然不!我讨论了space,但是时间效率呢?例如,搜索是我们希望我们的数据结构支持的一种常用方法,如果我们希望它更快!
在矩阵的情况下,搜索将是一个 O(1) 操作,这很不错,因为访问矩阵是一个常量操作。
然而,在矢量+列表的情况下,搜索将花费 O(L),其中 L
是我们的矢量总共具有的列表的平均大小。
那是哪一个?这取决于您的应用!
我也会尝试哈希表,它不需要排序并且 space 高效 (What is the space complexity of a hash table?)。
为每个用户设置一个固定大小 (90) 的访问详细信息的 Queue 怎么样?您可以将其概括为多个用户,主要优势是您不必担心维护最近 90 天的数据。
如果需要,您可以将队列转储到列表或数组并在 O(n) 中保留。正如您所提到的,no.of 存在的检查也将是 O(n)。
为每个客户创建一个 Queue data structure,其中包含带有访问日期的元素。
当客户访问健身房时,只需添加当前日期
Q[ClientIdx].Add(Today)
当您需要为他获取曲目时:
while (not Q[ClientIdx].Empty) and (Today - Q[ClientIdx].Peek > 90)
Q[ClientIdx].Remove //dequeue too old records
VisitCount = Q.Count
如果标准队列不可用,您可以使用多种语言的标准队列实现或基于 array/list 的简单自己的实现。
请注意,每条记录都添加和删除一次,因此每个 add/count 操作的分摊复杂度为 O(1)
我正在解决一个有趣的问题,其中对于每个用户,我想保留他最后 N 天的 activity。这可以应用于许多用例,一个这样简单的用例是:
对于每个用户 - 用户可以在某一天随机来健身房 - 我想获得他在过去 90 天内去健身房的总次数。
这对我来说是一个棘手的问题。
我的想法:我想存储一个向量,其中每个条目将确定一天,然后一个布尔值可能代表他的访问。要计数,只需对数组中的该部分进行线性处理就足够了。
最好的方法是什么?
根据您需要的复杂程度,存储每次客户访问的简单数组就足够了。
每次访问时,添加一个包含 date/time 的新条目。每天,运行 检查是否有任何客户包含超过 90 天的访问记录。第一个不够旧的记录意味着没有更多的记录可以检查,所以你可以安全地移动到下一个客户端。
希望对您有所帮助!
您的想法会奏效,但它真的 space 有效吗?
你的 data-structure 会是这样的:一个布尔二维向量(你可以把它想象成一个矩阵),其中每一行是一个用户,每一列是一天(排序),所以包括:
matrix of size
U x N
其中 U 是用户数。
要回答我最初提出的问题,您需要考虑这个矩阵密集的程度。如果它会很多,那么你做出了正确的选择,如果不是,那么你浪费了(很多)space。您可以在此处查看权衡。
当然,您必须考虑您的用例。在健身房的例子中,我认为这不会 space 有效,因为 most 人不是每天都去健身房(我认为),这将导致矩阵稀疏,这意味着我们浪费了 space.
另一个想法是使用单个矢量 os 大小 N
,其中对日期进行排序。每个条目都是一个链表,其中每个节点都是一个用户。
如果某个用户出现在某一天的列表中,则说明他那天去了健身房。
通过这种方法,我们根据需要精确分配了space,所以它是space最优的,不管我在矩阵案例中提到的密度如何.
然而,是这样吗?不,当然不!我讨论了space,但是时间效率呢?例如,搜索是我们希望我们的数据结构支持的一种常用方法,如果我们希望它更快!
在矩阵的情况下,搜索将是一个 O(1) 操作,这很不错,因为访问矩阵是一个常量操作。
然而,在矢量+列表的情况下,搜索将花费 O(L),其中 L
是我们的矢量总共具有的列表的平均大小。
那是哪一个?这取决于您的应用!
我也会尝试哈希表,它不需要排序并且 space 高效 (What is the space complexity of a hash table?)。
为每个用户设置一个固定大小 (90) 的访问详细信息的 Queue 怎么样?您可以将其概括为多个用户,主要优势是您不必担心维护最近 90 天的数据。
如果需要,您可以将队列转储到列表或数组并在 O(n) 中保留。正如您所提到的,no.of 存在的检查也将是 O(n)。
为每个客户创建一个 Queue data structure,其中包含带有访问日期的元素。 当客户访问健身房时,只需添加当前日期
Q[ClientIdx].Add(Today)
当您需要为他获取曲目时:
while (not Q[ClientIdx].Empty) and (Today - Q[ClientIdx].Peek > 90)
Q[ClientIdx].Remove //dequeue too old records
VisitCount = Q.Count
如果标准队列不可用,您可以使用多种语言的标准队列实现或基于 array/list 的简单自己的实现。
请注意,每条记录都添加和删除一次,因此每个 add/count 操作的分摊复杂度为 O(1)