【问题标题】:Is there a linear solution to determining whether a postorder sequence is a valid BST?是否存在确定后序序列是否为有效 BST 的线性解决方案?
【发布时间】:2014-08-18 01:19:07
【问题描述】:

问题:给定一个整数数组,确定它是否可以是 BST 的后序遍历序列。例如:[5, 7, 6, 9, 11, 10, 8] 返回 true,但 [7, 4, 6, 5] 返回 false。

我想知道我们是否可以在线性时间内做到这一点。这是我想出的N^2NlgN 的解决方案。

N^2 solution:扫描数组,检查根的左右子树的值分别小于和大于根的值。对每个子树重复。

NlgN solution:从输入数组的右到左构建一个 BST。跟踪我们可以在任何时候遇到的最大数量。每次我们插入一个左孩子时,这个最大数量都会更新到父节点。如果我们尝试插入一个大于跟踪的最大数量的节点,我们可以返回 false。

【问题讨论】:

    标签: performance algorithm data-structures tree binary-search-tree


    【解决方案1】:

    这是一个线性时间算法,比这个答案的最新版本简单得多。

    def checkbst(lst):
        # stack contains the values of nodes from which the current path departs right
        stack = [float('-inf')]
        # upperbound is the value of the leafmost node from which the path departs left
        upperbound = float('inf')
        for x in reversed(lst):
            # pop stack elements greater than or equal to x
            # stack[-1] is the top
            while stack[-1] >= x:
                upperbound = stack.pop()
            if x >= upperbound:
                return False
            # push
            stack.append(x)
        return True
    

    可以想象一个递归过程,它使用根值最后出现的事实,如下所示。从右到左扫描,直到找到小于根的值。在该值之后拆分数组的最大正确前缀。递归验证右半部分。验证左半部分的值都小于根,然后递归地验证一半。

    后面的递归处于尾部位置,可以转化为迭代。可以推迟检查值是否小于根,因为上限随时间单调递减。我们将递归堆栈的剩余部分保留在stack 中,即我们从中进行非尾递归的根值序列。内部循环确定调用堆栈中应考虑当前元素的程度。它是摊销的常数时间。

    【讨论】:

    • 这个算法我好像很难理解,你能举个例子,在[5, 7, 6, 9, 11, 10, 8]后序序列上尝试这个算法吗?
    • @dguan 在高层次上,它完全按照您的预期工作:通过拆分 [5, 7, 6, 7, 9, 11, 10, 8] -> [5, 7, 6 ] [9, 11, 10],然后是 [5, 7, 6] -> [5] [7],然后是 [9, 11, 10] -> [9] [11]。你肯定同意我们可以对有效的后序使用二分搜索来找到 root 之间的边界;我声称,即使数组不是那么有序,并且存在不止一个这样的边界,我们仍然会保持较弱的属性,即找到一个比根小的键,然后紧跟一个更大的键。当我们开始检查有问题的键时,我们随后会发现这种调皮行为。
    • 以上 cmets 是关于以前的版本。
    • 谢谢,这是一个非常好的解决方案。我没有注意到我们可以使用 Stack 而不是构建 BST!
    【解决方案2】:

    这里是 C++ 代码

    bool verifyPostorder(vector<int>& nums)
    {
         int high=INT_MAX,index=nums.size();
         for(int j=int(nums.size())-1;j>=0;--j)
      {
           if(nums[j]>high)return false;
           while(i<=int(nums.size())-1 && nums[j]<nums[i])
                 high=nums[i++];
           nums[--i]=nums[j];
      }
      return true;
    
    }
    

    你可以尝试按照这个写verifyPreorder。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-12
      • 2017-05-20
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      • 1970-01-01
      • 2020-09-07
      • 1970-01-01
      相关资源
      最近更新 更多