用代码解锁二叉树对称大挑战 — GPT带你飞

46 阅读3分钟

开始一道算法题

今天在力扣刷了一道题:

给你一个二叉树的根节点 root , 检查它是否轴对称

image.png
image.png
输入是一个数组,输出是布尔值,如果是一个对称二叉树,那就返回true;如果不是,那就返回false。
我第一次的代码是这样写的

/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isSymmetric = function (root) {
  // 计算二叉树的层数
  const tierLevel = Math.log2(root.length + 1);

  // 遍历每一层
  for (let i = 1; i <= tierLevel; i++) {
    let count = 0;
    // 计算当前层的左侧索引
    let leftIndex = Math.pow(2, i) + count;
    // 计算当前层的右侧索引
    let rightIndex = Math.pow(2, i + 1) - (count + 1);

    // 当左侧索引小于右侧索引时,继续比较
    while (leftIndex < rightIndex) {
      // 如果对应位置的节点值不相等,返回 false
      if (root[leftIndex - 1] !== root[rightIndex - 1]) {
        return false;
      }

      // 更新计数器和索引值,继续比较下一对节点
      count++;
      leftIndex = Math.pow(2, i) + count;
      rightIndex = Math.pow(2, i + 1) - (count + 1);
    }
  }

  // 如果所有对应位置的节点都相等,返回 true
  return true;
};

这个代码将会检查每一层的对应位置的节点是否相等。如果在遍历过程中发现有不相等的节点,函数会立即返回 false。如果所有对应位置的节点都相等,那么函数最后返回 true。

此处涉及到一些数学规律。一个满二叉树,从第一层开始排序,

  • 第一层节点节点序号是2^0
  • 第二层节点序号是2^1+0,2^1+1
  • 第三层节点序号是2^2+0,2^2+1,2^2+2,2^2+3
  • 第n层节点序号是2^(n-1)+0, 2^(n-1)+1, ...., 2^(n-1)+[2^(n-1)-1]

所以代码中的左侧索引为Math.pow(2, i) + count,右侧索引为Math.pow(2, i + 1) - (count + 1),目的是,先比较一层中的最左边和最右边,然后依次往中间比较,如果有不相等的就不对称,如果遍历完一层,就遍历下一层。

优化我的代码

我问GPT:上面的代码是否可以优化?

GPT:可以,下面是优化后的代码

// 定义 isSymmetric 函数,输入为一个表示二叉树的数组
var isSymmetric = function (root) {
  // 计算二叉树的层数
  const levels = Math.floor(Math.log2(root.length + 1));

  // 遍历每一层
  for (let level = 1; level < levels; level++) {
    // 计算当前层的起始索引
    const start = Math.pow(2, level) - 1;
    // 计算当前层的结束索引
    const end = Math.pow(2, level + 1) - 2;
    // 计算当前层的节点数
    const levelNodes = end - start + 1;

    // 遍历当前层的一半节点
    for (let i = 0; i < levelNodes / 2; i++) {
      // 计算当前对比节点的左侧索引
      const leftIndex = start + i;
      // 计算当前对比节点的右侧索引
      const rightIndex = end - i;

      // 如果对应位置的节点值不相等,返回 false
      if (root[leftIndex] !== root[rightIndex]) {
        return false;
      }
    }
  }

  // 如果所有对应位置的节点都相等,返回 true
  return true;
};

代码优化的点:

  1. 计算二叉树层级数,考虑的比我多,它把不完全二叉树都考虑进去了
  2. 在比较左右两侧二叉树的时,计算下标的方法比我要简洁

算法递归版代码

我问GPT: 在判断是否为对称二叉树有其他办法吗 GPT:有的,还可以将数组转成二叉树的形式,再进行递归判断,而且递归代码要更简洁 我:是嘛?快给我看看 GPT:好的,下面是实例代码

// 将数组转换为二叉树结构的函数,传入数组和起始索引(默认为0)
const arrayToTree = (array, index = 0) => {
  // 如果数组为空或索引超出范围,返回 null
  if (!array || array.length === 0 || index >= array.length) return null;

  // 创建当前节点并设置其值
  const currentNode = new TreeNode(array[index]);
  // 设置当前节点的左子节点
  currentNode.left = arrayToTree(array, 2 * index + 1);
  // 设置当前节点的右子节点
  currentNode.right = arrayToTree(array, 2 * index + 2);

  // 返回当前节点
  return currentNode;
};

// 检查二叉树是否对称的函数,传入一个表示二叉树的数组
const isSymmetric = (array) => {
  // 如果数组为空,返回 false
  if (!array || array.length === 0) return false;

  // 将数组转换为二叉树结构
  const tree = arrayToTree(array);

  // 定义递归函数来检查左右子树是否对称
  const isEqual = (left, right) => {
    // 如果左右子树都为 null,返回 true
    if (left === null && right === null) return true;
    // 如果左右子树有一个为 null,返回 false
    if (left === null || right === null) return false;

    // 检查左右子树的值是否相等,以及递归检查左右子树的子树是否对称
    return (
      left.val === right.val && isEqual(left.left, right.right) && isEqual(left.right, right.left)
    );
  };

  // 检查根节点的左右子树是否对称
  return isEqual(tree.left, tree.right);
};

我: 递归的方式确实更好理解了,也更加直观了,谢谢你 GPT:不客气,请问还有什么可以帮助你 我:嗯,将数组变成二叉树,你提供的方案是递归,请问有没有迭代版本 GPT: 有的,下面迭代版本

数组如何转成二叉树

// 根据给定的数组生成二叉树结构
const generateArray = (array) => {
    // 如果数组为空或长度为0,返回null
    if (!array || array.length === 0) return;
    
    // 初始化根节点并将其添加到队列中
    const node = new TreeNode(array[0]);
    const queue = [node];
    // 初始化数组索引
    let index = 1;

    // 当索引未到达数组末尾时,继续处理节点
    while (index < array.length) {
        // 从队列中取出当前节点
        const currentNode = queue.shift();
        
        // 如果数组当前索引的值不为null,则创建左子节点并将其添加到队列中
        if (array[index] !== null) {
            currentNode.left = new TreeNode(array[index]);
            queue.push(currentNode.left);
        }
        // 增加索引
        index++;
        
        // 如果索引未到达数组末尾且数组当前索引的值不为null,则创建右子节点并将其添加到队列中
        if (index < array.length && array[index] !== null) {
            currentNode.right = new TreeNode(array[index]);
            queue.push(currentNode.right);
        }
        // 增加索引
        index++;
    }
    // 返回根节点
    return node;
};

我:哇谢谢你

总结:

文章开头是一个算法题,判断一个二叉树是否对称,首先用的方法是一个直接数组判断法,后面GPT提供了用二叉树的数据结构,并且用迭代的方法判断是否对称。再后来又对数组转成二叉树的方法进行了追问。
这种体验真是不错,像跟着一个老师来学习😁