【问题标题】:Find next lower item in a sorted list在排序列表中查找下一个较低的项目
【发布时间】:2010-04-07 09:10:33
【问题描述】:

假设我有一个浮点数的排序列表。现在我想获取给定值的下一个较低项目的索引。通常的 for 循环方法的复杂度为 O(n)。由于列表已排序,因此必须有一种方法可以使用 O(log n) 获取索引。

我的 O(n) 方法:

index=0
for i,value in enumerate(mylist):
    if value>compareValue:
        index=i-1

有解决 O(log n) 问题的数据类型吗?

【问题讨论】:

标签: python


【解决方案1】:

bisect怎么样?

>>> import bisect
>>> float_list = [1.0, 1.3, 2.3, 4.5]
>>> i = bisect.bisect_left(float_list, 2.5)
>>> index = i - 1
>>> index
2

您可能必须单独处理搜索值小于或等于列表中最低/最左侧值的情况(在这种情况下为index == -1)。

根据您希望在相等情况下使用的索引,您可能必须改用bisect_right

【讨论】:

  • 我认为这不起作用:>>> float_list = [0, 0.5, 1, 1.5, 2, 2.5, 3] // >>> float_list[bisect.bisect_left(float_list, 2.1)] // 2.5 下一个较低的项目是 2
  • @paul:“不起作用”对我来说似乎有点夸张:),但我已经澄清了答案。您必须减去 -1 才能获得索引。
【解决方案2】:

您可以对数组/列表进行二进制搜索以获取您要查找的对象的索引并获取其下方的索引以获取较低的条目(假设实际上存在较低的条目!)。

见:Binary search (bisection) in Python

comparing floating point numbers求平等时要小心!

【讨论】:

    【解决方案3】:

    使用bisect 模块。功能

    bisect.bisect_left(mylist, compareValue)
    

    返回列表中项目的正确插入点以保持排序顺序。

    【讨论】:

      【解决方案4】:
      import bisect
      
      def next_lower_value(values_list, input_value):
          index= bisect.bisect_left(values_list, input_value)
          if index == 0: # there's not a "next lower value"
              raise NotImplementedError # you must decide what to do here
          else:
              return values_list[index - 1]
      
      >>> l= [11, 15, 23, 28, 45, 63, 94]
      >>> next_lower_value(l, 64)
      63
      >>> next_lower_value(l, 63)
      45
      >>> next_lower_value(l, 1000)
      94
      >>> next_lower_value(l, 1)
      Traceback (most recent call last):
        File "<pyshell#29>", line 1, in <module>
          next_lower_value(l, 1)
        File "<pyshell#26>", line 4, in next_lower_value
          raise NotImplementedError # you must decide what to do here
      NotImplementedError
      

      由于您请求的是 index 而不是下一个较低的值,请将函数 next_lower_value 更改为返回 index - 1 而不是 values_list[index - 1]

      【讨论】:

        【解决方案5】:

        回答关于数据类型的部分问题:一般来说,最适合在 O(log n) 时间内查找事物的数据类型(同时保持 O(1) 的插入和删除性能!)是二叉树。您可以通过做出一系列左右决策来找到其中的内容,这与您在线性列表中进行二进制搜索的方式非常相似,但 (IMO) 在概念上更直观一些。

        也就是说,根据我对 Python 的了解,二叉树似乎不在该语言的标准库中。对于您的应用程序,仅仅为此目的包含一个实现可能没有任何好处。

        最后,排序列表中的二叉树和二叉搜索都可以让您将搜索缩短一步:不必先搜索关键项目,然后再返回前一项目。相反,在每个比较步骤中,如果您遇到键值,就好像它太大了一样。这将导致您的搜索以下一个较小的值结束。仔细做,这也可能有助于解决bart提到的“浮点值几乎相等”的问题。

        【讨论】:

          【解决方案6】:

          如果我没看错的话,下一个较低的项目是列表中小于或等于 x 的第一个项目。 bisect documentation for searching sorted lists 给出了这个函数:

          def find_le(a, x):
              'Find rightmost value less than or equal to x'
              i = bisect_right(a, x)
              if i:
                  return a[i-1]
              raise ValueError
          

          【讨论】:

            【解决方案7】:
            def lower_bound(arr, x):
                left = 0
                right = len(arr)-1
                mid = -1
                if(arr[left] > x):
                    return mid
                while(left <= right):
                    mid = int(left + (right - left + 1) / 2)
                    if(left == right and right == mid):
                        return mid
                    if(x > arr[mid]):
                        left = mid
                    elif(x < arr[mid]):
                        right = mid - 1
                    else:
                        return mid
                return mid
            

            如果找到确切的元素,则此函数返回排序列表“arr”中元素的索引,否则返回小于给定数字“x”的最大元素的索引。如果没有元素小于给定的数字,则返回 -1。

            【讨论】:

            • 还有其他答案提供了 OP 的问题,它们是前段时间发布的。发布答案 see: How do I write a good answer? 时,请确保添加新的解决方案或更好的解释,尤其是在回答较老的问题时。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-11-03
            • 2010-10-26
            • 2019-12-09
            • 1970-01-01
            • 1970-01-01
            • 2017-03-02
            相关资源
            最近更新 更多