【问题标题】:Longest increasing subsequence with binary search二分查找的最长递增子序列
【发布时间】:2021-09-02 17:07:14
【问题描述】:

我正在尝试在 python 中实现一些算法,我需要帮助。 给定一些整数数组, 我想建立 BTS 并找到最长的增加子序列。 这个想法是为每个节点提供索引(按插入顺序) 接下来我们要从左树中取出所有索引并将它们放入堆栈 接下来我们要检查上面堆栈中的每个索引,如果我们在树索引中大于当前节点,如果是,我们将其插入堆栈并更新值 max ,这是我们堆栈中的元素数。

我在扫描树并将元素插入堆栈时需要帮助。

到目前为止,这是我的代码:

class Node:
    def __init__(self, key, index = -1):
        self.right = None
        self.left = None
        self.key = key
        self.index = index

    def __str__(self):
        return "key: %s, index: %s" % (str(self.key), str(self.index))  

def insert(root, key, value=-1):
    if root is None:
        root = Node(key, value)
    else:
        if key < root.key:
            root.left = insert(root.left, key, value)
        elif key > root.key:
            root.right = insert(root.right, key, value)
        else:
            pass
    return root

def LeftSideIndices(root):
    res = []
    if root:
        res = LeftSideIndices(root.left)
        res.append(root.index)
    return res

def InOrderWithInsert(root,A):
    newStack = []

    if root:
        for i in range(0, len(A)):
            newStack = upInOrder(root.left,A)
            if root.index > A[i]:
                newStack.append(root.key)
            newStack = newStack + upInOrder(root.right, A)
    return newStack

例子:

正确的堆栈应该是:s=[0,2,8,11]

【问题讨论】:

  • 你说的是你想做的,但不是你需要帮助的。
  • 您有什么特别的原因想用二叉搜索树来做这件事吗?构建 BST 至少是线性的,因此也只需扫描一次列表以找到最长的序列,而无需构建 BST。
  • 我更新了我需要帮助的内容。我想这样做的原因是,我在大学的“数据结构”课程的一些练习中看到了这个问题,我只在伪代码中找到了解决方案,如果可能的话,我想实现它。

标签: python algorithm stack binary-search-tree


【解决方案1】:

一些一般性说明:

  • 感谢提供MWE
  • 您的代码未定义 upInOrder,因此我们无法运行其中的一部分
  • nitpick:在insert 函数中,您的value 参数被传递给Node 构造函数的index 参数,命名令人困惑。
  • 重新表述您的问题以使其明确:“给定二叉搜索树,找到最长递增子序列”
  • LeftSideIndices 中有一个错误:它只返回左(大)子的索引,而不是整个树的左半部分的索引,例如:
    bst = insert(insert(insert(None, 2, 0), 0, 1), 1, 2)
    #            val=2,idx=0
    #            /
    #  val=0,idx=1
    #            \
    #         val=1,idx=2
    print(LeftSideIndices(bst))  # [1, 0]
    
  • 供参考:
    print("value | " + " | ".join(str(value).ljust(2) for value in A) + " |")
    print("index | " + " | ".join(str(index).ljust(2) for index in range(len(A))) + " |")
    # | value | 4  | 1  | 13 | 7  | 0  | 2  | 8  | 11 | 3  |
    # | index | 0  | 1  | 2  | 3  | 4  | 5  | 6  | 7  | 8  |
    
  • 正如 cmets 中所说,另一种解决方案是根本不使用 BST,只需在 A 中搜索 LIS(它使用更常见的算法)。我什至会说,使用 BST 会变得毫无意义,因为结果与 BST 结构无关,它由插入顺序严格定义,与考虑的数据结构无关。
  • 可能有多个不同的子序列具有相同的长度(可能是最长的),例如:
    bst = insert(insert(insert(insert(None, 1, 0), 22, 1), 14, 2), 15, 3)
    #     val=1,idx=0
    #               \
    #               val=22,idx=1
    #               /
    #       val=14,idx=2
    #               \
    #            val=15,idx=3
    
    # Expected LIS = { (1, 22),   (14, 15) }
    

我读了好几遍你的算法解释(稍微重新格式化):

  • 从左树中取出所有索引并将它们放入堆栈
  • 检查堆栈中的每个索引,如果我们在树索引中大于当前节点
    • 如果是,则将其插入堆栈并更新值 max,即堆栈中的元素数。

我不确定你的算法是否理解,而且我认为它不起作用。

我什至不确定这个问题是否有简单的解决方案。
您的索引分散在整个树中的方式会阻止节点知道其左侧和/或右侧子树中的哪些解决方案是有趣的,因为子树中的索引序列中存在太多漏洞,信息位于节点层级差距太大。

通常对于树算法,应用一些divide and conquer algorithm 很简单,但在这种情况下,我什至无法判断根节点如何递归判断哪个是最长的子序列,因为它的左子树和右子树的结果.

但在你的情况下,我觉得很难找到如何实现你想要的东西。而且我无法说服自己实际上有一种算法。所以我希望你能证明我错了。

【讨论】:

    猜你喜欢
    • 2012-03-22
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 2013-07-03
    • 2016-05-04
    相关资源
    最近更新 更多