Python - 在堆中获取小于n

时间:2015-11-10 09:37:14

标签: python algorithm heap dynamic-programming

我在Python中找不到以下功能时遇到了问题:

  

给定一组数字,如果不存在这样的数字,则返回小于或等于n的最大数字或返回None

例如,给定列表[1, 3, 7, 10]n = 9,函数将返回7.

我正在寻找类似于Java's TreeSet.lower的Python功能。

我可以使用其他数据结构。堆似乎合适。

O(n)解决方案对于问题的规模来说太慢了。我正在寻找一个O(log n)解决方案。

背景

我正在https://www.hackerrank.com/challenges/maximise-sum工作。可能的值范围为1 - 10 ^ 14,因此使用带二进制搜索的排序列表太慢。

我目前的想法是直接迭代Python's heapq backing array。我希望可能会有更多的Pythonic。

7 个答案:

答案 0 :(得分:3)

我认为您可以使用 bintrees 库:https://bitbucket.org/mozman/bintrees/src

示例:

tree = bintrees.RBTree()
In [10]: tree.insert(5,1) 
In [11]: tree.insert(6,1) 
In [12]: tree.insert(10,1)
tree.ceiling_item(5)  -> (5,1)

此操作的复杂性为O(logN)

答案 1 :(得分:2)

nextLowest  = lambda seq,x: min([(x-i,i) for i in seq if x>=i] or [(0,None)])

用法:

t = [10, 20, 50, 200, 100, 300, 250, 150]
print nextLowest(t,55)
> 50

我从similar question获取上述解决方案。

答案 2 :(得分:1)

如果你不能对数组的排序做出任何假设,那么我认为你能做的最好是O(n):

def largest_less_than(numlist, n):
    answer = min(numlist, key=lambda x: n-x if n>=x else float('inf'))
    if answer > n:
        answer = None
    return answer

如果问题是重复获取同一数据集中不同n值的最大值,则可能有一个解决方案是使用bucket sort将列表排序为O(n) ,然后重复使用bisect

答案 3 :(得分:0)

您可以使用selection algorithm。下面我为此提供了一个简单的算法:

numbers = [1, 3, 7, 10]
n = 9
largest_number = None
for number in numbers:    
    if number<=n:
        largest_number=number
    else:
        break

if largest_number:
    print 'value found ' + str(largest_number)
else:
    print 'value not found'

答案 4 :(得分:0)

如果您不必支持列表中的动态添加和删除,那么只需对其进行排序并使用二进制搜索来查找最大的&lt; n在O(log N)时间内。

答案 5 :(得分:0)

ig-melnyk的回答可能是完成这个问题的正确方法。但是由于HackerRank没有办法使用库,这里是我用来解决这个问题的Left-Leaning Red Black Tree的实现。

class LLRB(object):

    class Node(object):
        RED = True
        BLACK = False

        __slots__ = ['value', 'left', 'right', 'color']

        def __init__(self, value):
            self.value = value
            self.left = None
            self.right = None
            self.color = LLRB.Node.RED


        def flip_colors(self):
            self.color = not self.color
            self.left.color = not self.left.color
            self.right.color = not self.right.color


    def __init__(self):
        self.root = None


    def search_higher(self, value):
        """Return the smallest item greater than or equal to value.  If no such value
        can be found, return 0.

        """
        x = self.root
        best = None
        while x is not None:
            if x.value == value:
                return value
            elif x.value < value:
                x = x.left
            else:
                best = x.value if best is None else min(best, x.value)
                x = x.right

        return 0 if best is None else best

    @staticmethod
    def is_red(node):
        if node is None:
            return False
        else:
            return node.color == LLRB.Node.RED


    def insert(self, value):
        self.root = LLRB.insert_at(self.root, value)
        self.root.color = LLRB.Node.BLACK


    @staticmethod
    def insert_at(node, value):
        if node is None:
            return LLRB.Node(value)

        if LLRB.is_red(node.left) and LLRB.is_red(node.right):
            node.flip_colors()

        if node.value == value:
            node.value = value
        elif node.value < value:
            node.left = LLRB.insert_at(node.left, value)
        else:
            node.right = LLRB.insert_at(node.right, value)


        if LLRB.is_red(node.right) and not LLRB.is_red(node.left):
            node = LLRB.rotate_left(node)
        if LLRB.is_red(node.left) and LLRB.is_red(node.left.left):
            node = LLRB.rotate_right(node)

        return node

答案 6 :(得分:0)

您可以减少要查找的号码,直到找到为止。

此功能将找到fs中最大数<= n的位置,即整数排序列表。

如果没有小于或等于n的数字,则返回-1。

def findmaxpos(n):
  if n < fs[0]: return -1  
  while True:
    if n in fs: return fs.index(n)
    n-=1