找到函数的转折点

时间:2018-04-29 06:02:05

标签: python algorithm binary-search

我想要为我的函数输出True的第一个值。我目前有一个搜索工作正常,但我认为仍然有点低效。有谁能建议更好的二元搜索?我的代码如下,简化。

guess = 2
limits = [2, 2**35] #The search area

while True:
    if myFunction(guess) == False:
        limits[0] = max(limits[0], guess) #Limit the search area
        guess *= 2
    else:
        limits[1] = min(limits[1], guess) #Limit the search area
        guess = int((limits[0] + limits[1])/2) #The guess is the midpoint of the search area
        if myFunction(guess) == True and myFunction(guess-1) == False:
            return guess

1 个答案:

答案 0 :(得分:1)

这是找到单调递增或递减函数的平交的经典问题。正如您猜测的那样,binary search可以解决这个问题。你的代码有一些错误,这并不奇怪:

  

虽然这个想法很简单,但正确实施二进制搜索需要注意其退出条件和中点计算的一些细微之处。

因此,您应尽可能避免编写自己的二进制搜索。幸运的是,Python提供了一个库模块bisect,可以帮助您完成工作。

from bisect import bisect_left

MIN = 2
MAX = 2**35

def search(f):
   # Finds the first position of `True` in `f`
   return bisect_left(f, True, lo=MIN, hi=MAX + 1)

不要对bisect仅适用于可索引对象这一事实感到困惑:无需创建包含2**35元素的列表。您可以使用__getitem__语法来使用生成器对象。为此,请将您的函数封装在一个类中,并定义getter方法,该方法将为感兴趣点左侧的所有参数值返回False,否则返回True

def myFunction1(index):
   return index >= 1456
def myFunction2(index):
   return index >= 2
def myFunction3(index):
   return index >= MAX - 1

class F:
   def __init__(self, f):
      self.f = f
   def __getitem__(self, index):
      return self.f(index)

# testing code
print(search(F(myFunction1))) # prints 1456
print(search(F(myFunction2))) # prints 2
print(search(F(myFunction3))) # prints MAX - 1