难以解决O(logn)中的代码

时间:2013-11-22 15:31:19

标签: python algorithm

我写了一个函数,它按顺序获取一个唯一整数列表的输入(从小到大)。我应该在列表中找到一个与索引中的值匹配的索引。例如,如果L [2] == 2,则输出为真。 所以在我复杂度O(logn)之后,我现在想要找到有多少索引的行为与给定列表中的行为相同,具有相同的复杂度O(logn)。 我上传我的第一部分代码,第一部分和第二部分我需要帮助:

def steady_state(L):

    lower= 0
    upper= len(L) -1
    while lower<=upper:
        middle_i= (upper+ lower)//2
        if L[middle_i]== middle_i:
            return middle_i
        elif L[middle_i]>middle_i:
            upper= middle_i-1
        else:
            lower= middle_i +1
    return None


def cnt_steady_states(L):
    lower= 0
    upper= len(L) -1
    a=b=steady_state(L)
    if steady_state(L)== None:
        return 0
    else:
        cnt=1
        while True:

            if L[upper] == upper and a<=upper:
                cnt+= upper-a
                upper= a
            if L[lower]== lower and b>=lower:
                cnt+= b- lower
                lower = b

3 个答案:

答案 0 :(得分:2)

你所提供的限制是不可能的。您理论上可以实现的最佳复杂性是 O n )。

O ()假设最坏的情况(只是一个定义,你可以放弃那个部分)。在最糟糕的情况下,总是必须查看每个项目,以便检查它是否等于其索引。

如果您有更多限制,案例会发生变化(例如,这些数字都是整数,而且没有一个可能出现多次,即没有两个连续的数字相等)。也许是这样的?

编辑:

在听说实际上我的假设限制适用后(即只出现一次)我现在提出这种方法:您可以放心地假设您只能拥有一个连续范围,其中所有匹配的条目都位于其中。 I. e。你只需要找到一个下限和上限。然后,想要的结果将是该范围的大小。

使用二进制搜索可以安全地找到每个绑定,其中每个都有 O (log n )。

def binsearch(field, lower=True, a=0, b=None):
  if b is None:
    b = len(field)
  while a + 1 < b:
    c = (a + b) / 2
    if lower:
      if field[c] < c:
        a = c
      else:
        b = c
    else:  # search for upper bound
      if field[c] > c:
        b = c
      else:
        a = c
  return b if lower else a

def indexMatchCount(field):
  upper = binsearch(field, lower=False)
  lower = binsearch(field, b=upper+1)
  return upper - lower + 1

这是我用来测试的:

field = list({ random.randint(-10, 30) for i in range(30) })
field.sort()
upper = binsearch(field, lower=False)
lower = binsearch(field, b=upper+1)
for i, f in enumerate(field):
  print lower <= i <= upper, i == f, i, f

答案 1 :(得分:1)

假设负整数正常:

我认为关键是如果你得到的值小于你的索引,你知道左边的所有索引也与它们的值不匹配(因为整数是严格增加的)。此外,一旦获得其索引值大于索引的索引,右侧的所有内容都不正确(原因相同)。然后,您可以像在第一种情况下那样进行分治算法。有点像:

check middle index:
    if equal:
        count = count + 1 
        check both halves, minus this index
    elif value > index:
        check left side (lower to index)
    elif index > value:
        check right side (index to upper)

在最坏的情况下(每个索引都匹配该值),我们仍然需要检查每个索引。

如果整数是非负数,那么你就会知道更多。您现在也知道如果索引与值匹配,则左侧的所有索引也必须与值匹配(为什么?)。因此,你得到:

check middle index:
    if equal:
        count = count + indices to the left (index-lower)
        check the right side (index to upper)
    elif value > index:
        check left side (lower to index)
    elif index > value:
        ##Can't happen in this case

现在我们最糟糕的情况得到了显着改善。我们没有找到匹配且没有从中获取任何新信息的索引,而是在找到匹配的索引时获得大量信息,现在知道一半的索引匹配。

答案 2 :(得分:1)

如果“所有数字都是整数且它们只出现一次”,那么您只需对L[i]==i && L[i+1]!=i+1中的第一对数字进行二分搜索。

要允许否定整数,请检查是否L[0]<0,如果是,请在1..N之间搜索:
i>0 && L[i]==i && L[i-1]!=i-1。然后在i和N之间执行上一次搜索。