【问题标题】:Find offset sequence in an array of integers在整数数组中查找偏移序列
【发布时间】:2014-02-14 17:31:05
【问题描述】:

我有许多包含 500 到 1000 个整数的数组。我想在这些数组中找到某个序列模式的一部分的任何实例。例如,我有一个偏移模式

offset = [-15, -12, -5, -1, 1, 10, 20, 32]

和一个正整数的排序列表

A = [2, 8, 12, 15, 22, ...] # Length ~ 1000

我想找到所有这样的整数 N,使得对于 offset 中的每个 aN + aA 的一个元素。

但是,理想情况下,我可以为匹配 N 所需的 a 值的数量设置一个阈值。因此,如果我的偏移量为 3,那么可能只有 N - 12N - 1N + 20 是存在于 A 中的值,我想保留 N

我可以很容易地编写一个蛮力算法来测试这个条件 - 但是有成千上万个这样的数组来测试几个模式,我想知道是否有更好的方法来解决这个问题。谢谢。


根据要求,这里有一些蛮力算法的伪代码:

# Not perfect because it doesn't take into account possible boundary cutoffs
for a in A:
    new_offset = [x + a for x in offset]
    count = sum(x in A for x in new_offset)

    if count >= threshhold:
        # keep a, and work out N

【问题讨论】:

  • 如果您至少向我们展示该蛮力算法将是什么,它可能有助于准确地阐明您想要什么。
  • 绝对可以使用列表推导来做到这一点。
  • @wnnmaw:对于offset 中的as 中的至少一些N+aA 中。对于需要匹配的偏移值的数量,我需要一个可变阈值。 @mhlester,我会写一些伪代码
  • @user2852809,是的,当我重新阅读您的帖子时,我注意到了
  • 什么是典型的偏移长度,您希望看到的整数范围是多少(例如,数组中的所有整数是否都小于 10,000)? (对于长偏移和小范围,您最好使用快速傅里叶变换)

标签: python arrays algorithm


【解决方案1】:
offsets = [-15, -12, -5, -1, 1, 10, 20, 32]
A = {2, 8, 12, 15, 22, ...} # a set of length ~ 1000
N = range(min(A)+min(offsets),max(A)+max(offsets)+1)
THRESHOLD = 3

NN = [num for num in N if sum((1 for offset in offsets if num+offset in A)) >= THRESHOLD]

或者,一旦你通过 THRESHOLD 就短路

offsets = [-15, -12, -5, -1, 1, 10, 20, 32]
A = {2, 8, 12, 15, 22, ...} # a set of length ~ 1000
test_range = range(min(A)+min(offsets),max(A)+max(offsets)+1)
THRESHOLD = 3

N = set()
for value in test_range:
    count = 0
    for offset in offsets:
        if value+offset in A: count += 1
        else: continue
        if count == 3:
            N.add(value)
            break

【讨论】:

  • 但是如果 max(A) 是一个非常大的数字怎么办?如果我正确地遵循它,这将是非常低效的。
  • 将 A 设为集合而不是列表可能更有效?
  • @PeterdeRivaz 谢谢,好主意!对于这些优化,我通常的心理检查清单是:“他把它作为一组给我了吗?没有。他是否明确声明它们是唯一值?没有。”但是由于我们不关心顺序或 A 也不关心重复值(无论如何都会有不同的结果),所以没关系!
  • 所以我只是用 0 到 9,999 之间的 1000 个随机数列表对此进行了测试,它并没有花太长时间,最多大约半秒。不过需要注意的是,你会想在第三行写上大写字母 A
  • 你也应该修复A[0]A[-1],索引集是不可能的。 :)
【解决方案2】:

如果我正确理解了这个问题。在我看来,如果 len(offset)

例如,如果您的价值观是: 偏移量 = [-3,-1,1] A = [1, 3, 5, 7]

你会计算 [4、6、8、10] [2、4、6、8] [0, 2, 4, 6]

然后你会数: 0:1 2:2 4:3 6:3 8:2 10:1

所以 4 和 6 应该适用于 N。

这个复杂度是 O(len(offset) * len(A))

【讨论】:

    【解决方案3】:

    我认为这是与上述类似的算法,但不确定。

    from collections import Counter
    counters = Counter()
    
    # Python 2.6: 
    # from collections import defaultdict
    # counters = defaultdict(int)
    
    from itertools import product
    Aset = set(A)
    for aval, offset in product(A, offset):
        counters[aval-offset] += 1
    
    # 3 is the threshold here; change at will.
    [key for key, val in counters.items() if val > 3]
    

    似乎可以工作。我们在做什么:如果有一个数 N 使得 N+offset 在 A 中,那么我们可以去 A 中的那个值,并且 Aval-offset = N。小而愚蠢的例子:

    A = [1,3,5,10]
    offset = [-2, 5]
    

    有一个数字 5 符合此条件。然而,我们还不知道。这个数字是 3 + 2 和 10-5。我们将第一次遍历 -2,并通过将 2 加回每个 A 得到 [3, 5, 7, 12]。然后,我们将再次遍历 5,得到 [-4, -2 , 0, 5] 通过从每个 A 中减去 5。这给了我们这样的计数器:

    -4: 1
    -2: 1
     0: 1
     3: 1
     5: 2
     7: 1
    12: 1
    

    5 是唯一匹配两个条目的条目。

    在给定的偏移量和随机生成的 0 到 4000 之间的约 1000 个随机整数序列(实际最小/最大 6/3999,生成 1200 个数字)上,通过 list(set()) 删除重复项,然后已排序),创建字典需要约 2.5 毫秒。如果它很重要,对于这个算法,你真的不需要对 A 进行排序,但删除重复项是必要的(除非你真的希望它计算两次)。

    【讨论】:

      猜你喜欢
      • 2023-04-09
      • 2012-04-13
      • 2020-01-18
      • 2017-04-22
      • 2021-04-07
      • 2021-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多