【问题标题】:Efficiently counting the rolling number of consecutive unique values有效计算连续唯一值的滚动数量
【发布时间】:2021-05-02 13:33:23
【问题描述】:

给定

author = c("A","B","A","B","C","D","C")

我希望输出是以下任何一种:

[1] 1 2 2 2 3 4 2

或者

[1] 1 2 1 2 3 4 1

或者

[1] 2 4 1

第一个给出唯一字母的滚动数,第二个是一个计数器,每当一个字母重复时重置为 1,最后一个计算唯一运行的长度(即 A-B2,@987654327 @ 是 4B1)。

第一个实现是最好的,因为它永远不会错过一个连胜。

目前我有第三个实现:

author = c("A","B","A","B","C","D","C")
n = length(author)
streak = rep(0,floor(n/2))
i = 1; counter = 1
while (i <= n)
{
  p = duplicated(author[i:(i+35)])
  i_new = i + Position(function(x) x==TRUE, p) - 1
  streak[counter] = i_new - i
  i = i_new
  counter = counter + 1
}
streak

这会计算非重复项的数量,直到第一个重复项,并将索引位置更改为中断非重复项连续运行的元素。我确定这比跟踪我看到的元素并检查每个新元素是否重复要快。

它的输出是2 4 0(因为i+35 超出了给定author 的范围),这没关系,因为最后一个元素并不那么重要。我们也可以假设没有超过 35 的连续。

我的主要问题是这需要很长时间才能运行,因为真正的 author 向量很大。

我怎样才能更有效地执行这项任务?



编辑:按照@Dikran 的回答,更新后的代码是:

author = c("A","B","A","B","C","D","C")
authorList = unique(author)
authorVals = 1:length(authorList)
authorHash = setNames(authorVals, authorList) # in R internally is a hash table
authorTabl = rep(0, length(authorVals))
author = as.integer(revalue(author, authorHash))
n = length(author)
streak = rep(0,floor(n/2))
index = rep(0,floor(n/2))
i = 1; counter = 1; first = 1; last = 1
for (i in 1:n)
{
  authorTabl[author[last]] = authorTabl[author[last]] + 1
  while (authorTabl[author[last]] == 2)
  {
    authorTabl[author[first]] = authorTabl[author[first]] - 1
    first = first + 1
  }
  last = last + 1
  streak[counter] = last - first
  counter = counter + 1
}
streak

速度很快,而且:

[1] 1 2 2 2 3 4 2

【问题讨论】:

  • 作者集中有多少个不同的值?
  • @DikranMarsupial 有 4,000 位独立作者,但其中 40 位占该集合的 95%。总共有 2200 万个条目。

标签: r algorithm


【解决方案1】:

我的方法是有一个地图数据结构,每个作者都有一个条目,记录它在窗口中出现的次数。如果地图是使用Hash Table 实现的,每个作者有一个列表,那么平均查找时间将是 O(1) 复杂度(只有 4000 个作者的内存开销对于现代计算机来说并不太成问题)。大多数现代编程语言,如 C++、Java 或 Python,都有基于哈希映射的库实现,因此您无需从头开始编写代码。

创建变量“first”和“last”,它们给出当前唯一作者运行中的第一个和最后一个条目的索引。两者都被初始化为序列的第一个元素。增加“first”引用的作者在地图中的作者计数。

在每一步增加“last”并增加索引作者的作者计数。如果它已增加到 1,则它必须是运行中的新唯一条目。如果不是,那么我们在某处的运行中有重复,所以开始减少对应于“first”的作者计数,然后增加“first”。如果作者计数减少到零,那不是在当前运行中有重复的作者,所以我们必须继续。如果它减为 1,则您刚刚找到了已重复的上一个条目,因此运行的其余部分现在应该是唯一的(因为查看序列的下一个元素只能引入一个重复项)。

在每个阶段,“last”和“first”之间的差异为您提供了以“last”结尾的序列中唯一条目的运行长度。

该算法的计算复杂度在序列元素的数量上是线性的,在作者数量上是恒定的(因为哈希表查找是 O(1))。我认为很难做得比线性时间更好!

我希望我已经正确理解了这个问题,但这就是我的方法。

【讨论】:

  • 是的,哈希表查找非常快,只要 has 函数均匀分布作者即可。如果您使用字符串和映射的库实现,那么它很可能使用高效的哈希函数,所以您应该没问题。诀窍是哈希表中的列表数量与作者数量相同。这样,平均而言,您要查找的作者将是哈希表中该列表中唯一的作者。这个技巧在某些操作系统的内存管理器中使用,所以它快速
  • 如果哈希表足够大,无论频率如何,查找时间都是一样的,所以可能不会有太大区别。在加速大规模编程任务时,了解正确的数据结构通常至关重要。
  • 这种方法对我来说是全新的,但看起来非常好。我现在就试试。感谢您的宝贵时间!
  • 没问题,相当有趣的编程挑战;o)
  • 我已经添加了更新的代码,它的运行速度比以前快了 120 倍!我最终将作者值转换为整数 (1:4000),然后使用简单的索引来查找 authorTabl 向量中的值。
【解决方案2】:

在长度为 set 的循环中执行以下操作: 如果输入是“A”,则将温度值增加到 1。然后在第一次看到“B”后再次增加温度,依此类推。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多