面试题33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

思路

  • 后序遍历性质: [ 左子树 | 右子树 | 根节点 ] ,即遍历顺序为 “左、右、根” 。
  • 二叉搜索树性质: 左子树任意节点的值 < 根节点的值;右子树任意节点的值 > 根节点的值。

方法一:递归分治
子树递推性质: 对于 [ 左子树 | 右子树 | 根节点 ] 中的左(右)子树,仍满足后序遍历和二叉搜索树性质。
因此,可以通过递归判断每个子树的 正确性 (即其后序遍历是否满足二叉搜索树性质) ,若所有子树都正确,则此序列为二叉搜索树的后序遍历。

  • 终止条件:i≥ji \geq jij ,说明子树节点少于或等于 111 个,无需判别正确性,因此直接返回 truetruetrue

  • 递推工作:

    1. 划分左右子树: 遍历后序遍历的 [i,j][i, j][i,j] 区间元素,寻找 第一个大于根节点(即 postorder[j]postorder[j]postorder[j] )的节点,索引记为 mmm 。此时,可划分出左子树区间 [i,m−1][i,m-1][i,m1] 、右子树区间 [m,j−1][m, j - 1][m,j1] 、根节点索引 jjj
    2. 判断是否满足二叉搜索树性质:
      • 右子树区间 [m,j−1][m, j-1][m,j1] 内的所有元素都应 >>> postorder[j]postorder[j]postorder[j] 。实现方式为遍历,当遇到 ≤postorder[j]\leq postorder[j]postorder[j] 的元素则跳出;后续可通过 l=jl = jl=j 判断是否满足二叉搜索树性质。
      • 左子树区间 [i,m−1][i, m - 1][i,m1] 内的所有元素都应 <<< postorder[j]postorder[j]postorder[j] 。而第 1.划分左右子树 步骤已经保证左子树区间的正确性,因此只需要判断右子树区间即可。
  • 返回值: 所有子树都需正确才可判定正确,因此使用 与逻辑符 and 连接。

    1. l==jl == jl==j 判断此树是否正确。
    2. recur(i,m−1)recur(i, m - 1)recur(i,m1) 判断 此树的左子树 是否正确。
    3. recur(m,j−1)recur(m, j - 1)recur(m,j1) 判断 此树的右子树 是否正确。

代码:

class Solution:
    def verifyPostorder(self, postorder: [int]) -> bool:
        def recur(i, j):
            if i >= j: 
                return True
            l = i
            while postorder[l] < postorder[j]: 
                l += 1
            m = l
            while postorder[l] > postorder[j]: 
                l += 1
            return l == j and recur(i, m - 1) and recur(m, j - 1)

        return recur(0, len(postorder) - 1)
复杂度分析:
  • 时间复杂度 O(N2)O(N^2)O(N2) 每次调用 recur(i,j)recur(i,j)recur(i,j) 减去一个根节点,因此递归占用 O(N)O(N)O(N) ;最差情况下(即当树退化为链表),每轮递归都需遍历树所有节点,占用 O(N)O(N)O(N)
  • 空间复杂度 O(N)O(N)O(N) 最差情况下(即当树退化为链表),递归深度将达到 NNN
发布了88 篇原创文章 · 获赞 31 · 访问量 5055

猜你喜欢

转载自blog.csdn.net/weixin_43455338/article/details/104943741