二叉树的最近公共祖先 - 力扣(LeetCode)

99 阅读2分钟

在leetcode上要到这么一个二叉树的题目,为了解决测试这个题目,写了一些其他的工具函数;并进行了性能优化,效率在leetcode上击败了97%,在这儿记录一下。

方案一

function lowestCommonAncestor1(
  root: TreeNode | null,
  p: TreeNode | null,
  q: TreeNode | null
): TreeNode | null {
  if (!root) {
    return null;
  }
  if (p === q) {
    return root;
  }
  if (root === p || root === q) {
    if (pIsFatherNodeQ(root, root === p ? q : p)) {
      return root;
    }
    return null;
  }
  const l = lowestCommonAncestor1(root.left, p, q);
  if (l) return l;
  const r = lowestCommonAncestor1(root.right, p, q);
  if (r) return r;
  let x = find(root.left, p, q);
  if (!x) return null;
  x = x === p ? q : p;
  let y = find(root.right, x, x);
  if (y) return root;
  return null;
  function find(root, p, q) {
    if (!root) {
      return false;
    }
    if (root === p || root === q) {
      return root;
    }
    return find(root.left, p, q) || find(root.right, p, q);
  }
}

优化方案二:

//优化查找最近的公共父节点

function lowestCommonAncestor(
  root: TreeNode | null,
  p: TreeNode | null,
  q: TreeNode | null
) {
  function find(root, p, q) {
    if (!root) {
      return null;
    }
    if (root === p || root === q) {
      if (pIsFatherNodeQ(root, root === p ? q : p)) {
        return root; //root是公共父节点,一个是父节点,一个是子节点
      }
      return { p: root };
    }
    const l = find(root.left, p, q);
    if (l && !l.p) {
      return l; //两个都在左子树
    }
    const r = find(root.right, p, q);
    if (r && !r.p) {
      return r; //两个都在左子树
    }
    if (l && r && l?.p !== r?.p) {
      return root;
    }
    return l || r;
  }
  const res = find(root, p, q);
  if (res && !res.p) return res;
  return false;
}

其他工具函数

  • 树数据结构
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
    this.val = val === undefined ? 0 : val;
    this.left = left === undefined ? null : left;
    this.right = right === undefined ? null : right;
  }
}
  • 查询p是不是q的父节点
//查询p是不是q的父节点
function pIsFatherNodeQ(p, q) {
  if (!p) {
    return null;
  } else {
    if (p === q || p.left === q || p.right === q) {
      return true;
    }
    return pIsFatherNodeQ(p.left, q) || pIsFatherNodeQ(p.right, q);
  }
}
  • 根据层级生成二叉树
//根据层级生成二叉树
function getTree(treeLever = 0) {
  let root = new TreeNode(-1);
  let i = 0;
  function toTreeNode(node, level) {
    if (level < treeLever) {
      node.left = new TreeNode(i++);
      toTreeNode(node.left, level + 1);
      node.right = new TreeNode(i++);
      toTreeNode(node.right, level + 1);
    } else {
      return;
    }
  }
  toTreeNode(root, 0);
  return root;
}
  • 根据数组生成二叉树---层序遍历(根据leetcode生成测试案例数据)
//根据数组生成二叉树---层序遍历
function getTreeByArray(array = []) {
  if (!array.length) return null;
  let root = new TreeNode(array[0]);
  let p = [root];
  let t = [];
  let i = 1;
  while (i < array.length) {
    for (let j = 0; j < p.length; j++) {
      if (p[j]) {
        array[i] ? (p[j].left = new TreeNode(array[i++])) : i++;
        array[i] ? (p[j].right = new TreeNode(array[i++])) : i++;
        t.push(p[j]?.left || null);
        t.push(p[j]?.right || null);
      } else {
        i += 2;
      }
    }
    p = t;
    t = [];
  }
  return root;
}
  • 根据值查询节点
//根据值查询节点
function findNodeBayVal(root, val) {
  if (!root) return;
  if (root.val === val) {
    return root;
  } else {
    return findNodeBayVal(root.left, val) || findNodeBayVal(root.right, val);
  }
}

测试

// const root = getTree(5);
const root = getTreeByArray([1, 2, 3, null, 4]);
const p = findNodeBayVal(root, 4);
const q = findNodeBayVal(root, 3);
const node = lowestCommonAncestor(root, p, q); //3debugger;