二叉树的递归和层序遍历 | 用TypeScript写层序遍历 226.翻转二叉树 101.对称二叉树 | 代码随想录D15

88 阅读2分钟

二叉树的递归和层序遍历

层序遍历

function levelOrder(root: TreeNode | null): number[][] {
  let helperQueue: TreeNode[] = [];
  let ret: number[][] = [];
  let curNode:TreeNode;
  let tempArr:number[] = [];
  if(root !== null) helperQueue.push(root);
  while(helperQueue.length > 0){
    for(let i = 0,len = helperQueue.length; i < len; i++){
      curNode = helperQueue.shift()!;
      tempArr.push(curNode.val);
      if(curNode.left !== null){
        helperQueue.push(curNode.left);
      }
      if(curNode.right !== null){
        helperQueue.push(curNode.right);
      }
    }
    ret.push(tempArr);
    tempArr = [];
  }
  return ret;
};

翻转二叉树

递归

①出口:root为空是出口,此时终止;

②单层循环的逻辑:每次都借temp进行节点的交换。

前序遍历是先交换整个左右子树 后交换具体节点;

后序遍历是先交换子树的具体节点,再交换整颗子树;

后序遍历比较特殊,交换左子树的具体节点后,再交换左右子树,这样最后交换的就是原来的右子树,现在的左子树的具体节点。

代码重复性比较高,按思路拖一下就都ok了:

//递归-前序遍历
function invertTree(root: TreeNode | null): TreeNode | null {
  if(root === null) return root;
  let temp: TreeNode | null = root.left;
  root.left = root.right;
  root.right = temp;
  invertTree(root.left);
  invertTree(root.right);
  return root;
};
​
//*递归中序遍历
function invertTree(root: TreeNode | null): TreeNode | null {
  if(root === null) return root;
  invertTree(root.left);
  let temp: TreeNode| null = root.left;
  root.left = root.right;
  root.right = temp;
  invertTree(root.left);
  return root;
};
​
//递归-后序遍历
function invertTree(root: TreeNode | null): TreeNode | null {
  if(root === null) return root;
  invertTree(root.left);
  invertTree(root.right);
  let temp: TreeNode| null = root.left;
  root.left = root.right;
  root.right = temp;
  return root;
};

迭代

可以使用栈或者队列来进行;

使用栈时,注意出栈顺序,根据出栈顺序的不同来区分前中后序遍历;

栈模拟中的中序遍历和后序遍历都需要添加null作为标记;

使用队列时,进行层序遍历的通用写法,最后一层的节点仍然要做交换,但没有左右节点继续压入队列了,队列为空时进行返回。

//栈模拟前序遍历
//根据栈先进后出的特性,不用使用null作为标记
function invertTree(root: TreeNode | null): TreeNode | null {
  let tempStack: TreeNode[] = [];
  let curNode: TreeNode | null = null;
  let tempNode: TreeNode | null = null;
  if(root !== null) tempStack.push(root);
  while(tempStack.length > 0){
    curNode = tempStack.pop();
      //这里是先交换还是先入栈并不影响功能实现
    tempNode = curNode.left;
    curNode.left = curNode.right;
    curNode.right = tempNode;
    if(curNode.right) tempStack.push(curNode.right);
    if(curNode.left) tempStack.push(curNode.left);
  }
  return root;
};
​
// 栈模拟二叉树中序遍历
function invertTree(root: TreeNode | null): TreeNode | null {
  let tempStack: TreeNode[] = [];
  let curNode: TreeNode | null = null;
  let tempNode: TreeNode | null = null;
  if (root !== null) tempStack.push(root);
  while (tempStack.length > 0) {
    curNode = tempStack.pop();
    if (curNode !== null) {
      if (curNode.right) tempStack.push(curNode.right);
      tempStack.push(curNode);
      tempStack.push(null);
        //这里的 null作为标记使用
      if (curNode.left) tempStack.push(curNode.left);
    }
    else {
    //读取到null标记时进行交换
      curNode = tempStack.pop();
      tempNode = curNode.left;
      curNode.left = curNode.right;
      curNode.right = tempNode;
    }
  }
  return root;
};
​
// 栈模拟二叉树后序遍历
// 就是中序遍历稍微交换一下位置
function invertTree(root: TreeNode | null): TreeNode | null {
  let tempStack: TreeNode[] = [];
  let curNode: TreeNode | null = null;
  let tempNode: TreeNode | null = null;
  if (root !== null) tempStack.push(root);
  while (tempStack.length > 0) {
    curNode = tempStack.pop();
    if (curNode !== null) {
      if (curNode.right) tempStack.push(curNode.right);
      if (curNode.left) tempStack.push(curNode.left);
      tempStack.push(curNode);
      tempStack.push(null);
    }
    else {
      curNode = tempStack.pop();
      tempNode = curNode.left;
      curNode.left = curNode.right;
      curNode.right = tempNode;
    }
  }
  return root;
};
​
//队列模拟层序遍历
//层序遍历加上题目要求的操作代码
function invertTree(root: TreeNode | null): TreeNode | null {
  let tempQueue: TreeNode[] = [];
  let tempNode: TreeNode | null;
  let curNode: TreeNode | null;
  if(root !== null) tempQueue.push(root);
  while(tempQueue.length > 0){
    for(let i = 0, len = tempQueue.length; i < len; i++){
      curNode = tempQueue.shift();
      tempNode = curNode.left;
      curNode.left = curNode.right;
      curNode.right = tempNode;
      if(curNode.left) tempQueue.push(curNode.left);
      if(curNode.right) tempQueue.push(curNode.right);
      //最后一层的节点仍然要做交换,但没有左右节点继续压入队列了
    }
  }
  return root;
};
​

对称二叉树

递归

终止条件

节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true

此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:

  • 左右都不为空,比较节点数值,不相同就return false

此时左右节点不为空,且数值也不相同的情况我们也处理了。

执行的功能性代码

比较外层outside是否相等left->left === right->right

比较内层inside是否相等left->right === right->left

返回比较结果outside && inside

function isSymmetric(root: TreeNode | null): boolean {
  // 递归写法
  function compare(left: TreeNode | null, right: TreeNode | null): boolean {
    if(left === null && right !== null) return false;
    else if(left !== null && right === null) return false;
    else if(left === null && right === null) return true;
    else if(left.val !== right.val) return false;
    let outside = compare(left.left, right.right);
    let inside = compare(left.right, right.left);
    return outside && inside;
  }
  if(root === null) return true;
  return compare(root.left, root.right);
};
​

层序

这题栈和队列区别不大,因为出栈(出队列)时只需要保证同时出了两个数就可以,而出数顺序对结果无影响(我们只需要比较两数是不是相等)。

function isSymmetric(root: TreeNode | null): boolean {
  // 队列模拟-迭代写法
  let tempQueue: TreeNode[] = [];
  let tempNode1: TreeNode | null;
  let tempNode2: TreeNode | null;
  if (root) {
    tempQueue.push(root.left);
    tempQueue.push(root.right);
  }
  while (tempQueue.length > 0) {
    tempNode1 = tempQueue.shift();
    tempNode2 = tempQueue.shift();
    if (tempNode1 === null && tempNode2 === null) continue;
    if (tempNode1 === null || tempNode2 === null) return false;
    if (tempNode1.val !== tempNode2.val) return false;
    tempQueue.push(tempNode1.left);
    tempQueue.push(tempNode2.right);
    tempQueue.push(tempNode1.right);
    tempQueue.push(tempNode2.left);
  }
  return true;
};