python DBF 倒遍历 python倒序遍历数组_由双遍历序列构造二叉树

20200925

题目:[1]

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:你可以假设树中没有重复的元素。

例如,给出:

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

返回如下的二叉树:

3
   / \
  9  20
    /  \
   15   7

    3
   / \
  9  20
    /  \
   15   7

抛砖引玉


python DBF 倒遍历 python倒序遍历数组_由双遍历序列构造二叉树_02

抛砖引玉

思路

参数:

  • 中序遍历的数组
  • 后续遍历的数组

思路

  • 借助后续遍历的节点找到每层子树的根节点
  • rootIndex:二叉子树在后续遍历数组中的位置索引
  • leftIndex:二叉子树的左子树在后续遍历数组中的位置索引
  • rightIndex:二叉子树的右子树在后续遍历数组中的位置索引

查找根节点,及当前根节点左右子节点的逻辑:

  1. 后序遍历数组倒序遍历依次作为根节点
  2. 当前根节点的的左右子节点从中序遍历数组中查找:
  • 这个节点的左节点在中序遍历数组中这个元素的前一位
  • 这个节点的右节点在中序遍历数组中这个元素的后一位

深度优先搜索(DFS)

递归参数:

  • 左子树根节点在 postorder 中的索引
  • 右子树根节点在 postorder 中的索引

终止条件:

因为后续遍历是先遍历左子树再遍历右子树最后遍历根节点, 那么右子树的索引一定大于左子树的索引,当不满足是说明节点遍历完成,终止递归

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} inorder  中序遍历
 * @param {number[]} postorder 后序遍历
 * @return {TreeNode}
 */
var buildTree = function(inorder, postorder) {
  let rootIndex = postorder.length - 1,
    map = new Map()
  // 记录在中序遍历数组中每个节点的位置,方便在得到根节点时查找左右子树节点
  for (let i = 0; i     map.set(inorder[i], i)
  }
  function dfs(leftIndex, rightIndex) {
    if (leftIndex > rightIndex) return null
    let root = new TreeNode(postorder[rootIndex]),
      i = map.get(postorder[rootIndex])
    rootIndex--
    root.right = dfs(i + 1, rightIndex)
    root.left = dfs(leftIndex, i - 1)
    return root
  }
  return dfs(0, inorder.length - 1)
}

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {number[]} inorder  中序遍历
 * @param {number[]} postorder 后序遍历
 * @return {TreeNode}
 */
var buildTree = function(inorder, postorder) {
  let rootIndex = postorder.length - 1,
    map = new Map()
  // 记录在中序遍历数组中每个节点的位置,方便在得到根节点时查找左右子树节点
  for (let i = 0; i     map.set(inorder[i], i)
  }
  function dfs(leftIndex, rightIndex) {
    if (leftIndex > rightIndex) return null
    let root = new TreeNode(postorder[rootIndex]),
      i = map.get(postorder[rootIndex])
    rootIndex--
    root.right = dfs(i + 1, rightIndex)
    root.left = dfs(leftIndex, i - 1)
    return root
  }
  return dfs(0, inorder.length - 1)
}

迭代

倒序遍历中序遍历数组(inorder):

  • 二叉树的遍历逻辑变成了:先遍历右孩子,再遍历根节点,最后遍历左孩子

倒序遍历后序遍历数组(postorder):

  • 二叉树的遍历逻辑变成了:先遍历根节点,再遍历右孩子,最后遍历左孩子

那么,倒序遍历后序遍历数组数组时,两个相邻的节点[a,b],两个节点在二叉树中的关系:

  1. b 是 a 的右子树上的节点
  2. a 没有右子树,并且 b 是与 a 子树相连的的左子树上的节点

实现

  • postorder 中最后一个元素是整个二叉树的根节点
  • 倒序遍历 postorder,inorder:
  • inorder 中先遇到右子树上的节点:
  • 不等于上一个生成子树的节点,则说明是上一个子树的右节点即情况 1,生成子树追击到上一个子树的 right 上
  • 等于上一个生成子树的节点,则说明在 inorder 中遍历到了根节点,即情况 2,那么 inorder 继续遍历先遇到的应该是这个根节点对应子树的左节点
var buildTree = function(inorder, postorder) {
  let rootIndex = postorder.length - 1,
    root = new TreeNode(postorder[rootIndex]),
    // 维护下一次遍历追击子树的最新子树
    queue = [root],
    inorderIndex = inorder.length - 1

  rootIndex--

  while (rootIndex >= 0) {
    let node = queue[queue.length - 1],
      nodeVal = postorder[rootIndex]
    // 不等于上一个生成子树的节点,则说明是上一个子树的右节点
    if (node.val !== inorder[inorderIndex]) {
      node.right = new TreeNode(nodeVal)
      queue.push(node.right)
    } else {
      // 维护inorder的倒序遍历索引跳过已经生成树的根节点
      while (
        queue.length &&
        queue[queue.length - 1].val === inorder[inorderIndex]
      ) {
        node = queue.pop()
        inorderIndex--
      }
      // 情况 2
      node.left = new TreeNode(nodeVal)
      queue.push(node.left)
    }

    rootIndex--
  }

  return root
}

var buildTree = function(inorder, postorder) {
  let rootIndex = postorder.length - 1,
    root = new TreeNode(postorder[rootIndex]),
    // 维护下一次遍历追击子树的最新子树
    queue = [root],
    inorderIndex = inorder.length - 1

  rootIndex--

  while (rootIndex >= 0) {
    let node = queue[queue.length - 1],
      nodeVal = postorder[rootIndex]
    // 不等于上一个生成子树的节点,则说明是上一个子树的右节点
    if (node.val !== inorder[inorderIndex]) {
      node.right = new TreeNode(nodeVal)
      queue.push(node.right)
    } else {
      // 维护inorder的倒序遍历索引跳过已经生成树的根节点
      while (
        queue.length &&
        queue[queue.length - 1].val === inorder[inorderIndex]
      ) {
        node = queue.pop()
        inorderIndex--
      }
      // 情况 2
      node.left = new TreeNode(nodeVal)
      queue.push(node.left)
    }

    rootIndex--
  }

  return root
}