我实际上在一段代码中工作,该代码将采用通用枚举和给定长度,并将返回在指定长度的枚举中找到的最频繁的模式以及它出现的次数。
因此,我的方法具有以下特征:
public static IEnumerable<T> ExtractFixedLengthPatter<T>(IEnumerable<T> source, int length, out int timesFound) { ... }
我实现这个的方式如下(我不会发布相应的代码,它有点长):
比方说,给出一个可枚举的整数:121234161221
,模式长度为2
我构建了以下树:
[1] -- [2] {count: 3}
-- [6] {count: 1}
[2] -- [1] {count: 2}
-- [2] {count: 1}
-- [3] {count: 1}
[3] -- [4] {count: 1}
[4] -- [1] {count: 1}
[6] -- [1] {count: 1}
我构建这个树的方法是迭代流,并在每次迭代中创建一个自定义迭代器,它从当前位置获取第一个length
项并填充树:
1rst outer iteration: {1}
Fixed length iterator: {1}
{2}
2nd outer iteration: {2}
Fixed length iterator: {2}
{1}
等等......
然后,我只是识别具有最大计数的最终节点,并遍历树,获得最频繁的模式反转。我扭转了模式,我已经完成了。
这个算法工作得非常好并且非常快。问题是,一位同事声称它有一个严重的错误。考虑以下情况:
111111
明显最常见的长度2
模式是11
。问题是,在枚举中出现了多少次?我的同事声称正确的答案是3
:
111111
11
11
11
我的算法返回5
:
111111
11
11
11
11
11
哪一个是正确答案?我倾向于相信它5
,但如果它3
,是否有人看到一种简单的方法我可以调整或改变算法以辨别这种情况?
答案 0 :(得分:1)
如果问题是“{{ngMeta.description}}
中出现11
次”,则只有一个答案:五次 - 在索引0,1,2,3和4处。
您的同事正在回答一个不同的问题 - 111111
中包含11
模式的多个非重叠副本,实际上是三个:在索引0,2和4。
我们需要非重叠的副本,我不知道如何调整现有的算法,我不想浪费时间来编写它;它的工作快速有效。也许存储每个节点的索引信息,并进行最终通过检查索引和模式长度以删除重叠副本?
您可以通过最少的修改重复使用算法。保留在每个叶节点上找到匹配项的最后一个元素的索引,以及当前保留的总计数。当您的算法到达叶子并准备增加总计数时,它应该检查先前索引是否至少从当前索引返回111111
个项目。如果它超过n
个项目,则递增计数;否则,忽略这个序列。
答案 1 :(得分:1)
如果您需要调整方法以使用同事的计数程序,您可以这样做:
count
字段除外),将其命名为lastIndex
,以存储导致count
递增的最后一个位置最后一个节点; count
增加时,首先检查它是否与此序列的前一次出现(已知在lastIndex
处开始)重叠。条件可能如下所示:if (node.lastIndex == INVALID_INDEX || node.lastIndex + length <= iterator.currentIndex()) {
node.count++;
node.lastIndex = iterator.currentIndex();
}