在二叉树中找到两个节点的最近公共祖先 & 判断一棵二叉树是否为搜索二叉树和完全二叉树

在二叉树中找到两个节点的最近公共祖先#

题目:在二叉树中找到两个节点的最近公共祖先

《程序员代码面试指南》第49题 P155 难度:原问题 士★☆☆☆ 进阶问题 尉★★

原问题解法,后序遍历二叉树,假设遍历到的当前节点cur。因为是后序遍历,所以先处理cur的两棵子树。假设处理cur左子树返回节点left,处理右子树返回节点right

  1. 如果cur==null,或者o1o2,则返回cur
  2. 如果left和right都为空,说明cur整棵子树上没有发现过o1或o2,返回null
  3. 如果left和right都不为空,说明左子树上发现过o1或o2,右子树上也发现过o2或o1,说明o1向上与o2向上的过程中,首次在cur相遇返回cur
  4. 如果 left和right有一个为空另一个不为空,假设不为空的那个记为node,此时node有两种可能,要么node是o1或o2中的一个,要么node已经是o1和o2的最近公共祖先。不管是哪种情况,直接返回node即可。
public Node lowestAncestor(Node head, Node o1, Node o2) {
    if (head == null || head == o1 || head == o2) {
        return head;
    }
    Node left = lowestAncestor(head.left, o1, o2);
    Node right = lowestAncestor(head.right, o1, o2);
    if (left != null && right != null) {
        return head;
    }
    return left != null ? left : right;
}

进阶问题核心在于花较大力气建立一种记录,以后执行每次查询时就可以完全根据记录进行查询

书上有2种记录的结构,一是建立二叉树中每个节点对应的父节点信息,二是直接建立任意两个节点之间的最近公共祖先记录

第一种建立的时间复杂度和额外空间复杂度都为O(N)查询的时间复杂度为O(h)

第二种建立的时间复杂度和额外空间复杂度都为O(N²)查询的时间复杂度为O(1)

具体算法的步骤与实现见书P157-160。

判断一棵二叉树是否为搜索二叉树和完全二叉树#

题目:判断一棵二叉树是否为搜索二叉树和完全二叉树

《程序员代码面试指南》第46题 P150 难度:士★☆☆☆

判断是否为搜索二叉树,直接检验中序遍历序列的单调递增性即可。当然也可以用树形dp套路来判断(虽然确实麻烦了点),使用ReturnType包装返回值类型,通过判断左右子树是否都满足搜索二叉树,以及和子树的根节点联合起来做判断……不做过多赘述。(书上用了Morris遍历,暂时不看)

另外也可以在中序遍历的途中就去逐一判断单调递增性,以下为摘自牛客网上该题讨论区某代码:

private int pre = 0;
private boolean isBST(node root) {
    //是否二叉搜索树
    if(root == null) return true;
    boolean left = isBST(root.left);
    if(left) {
        if(pre > root.val) return false;
        pre = root.val;
    }
    return left && isBST(root.right);
}

写的还不错,就是得在方法外定义一个变量来记录上个值。

判断是否为完全二叉树,依据以下标准:

  1. 按层遍历二叉树,从每层的左边向右边依次遍历所有的节点。
  2. 如果当前节点有右孩子节点,但没有左孩子节点,则直接返回false
  3. 如果当前节点并不是左右孩子节点全有,那么之后的节点必须都为叶节点否则返回false
  4. 遍历过程中如果不返回false,则遍历结束后返回true

我自己是根据定义“一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。”来编写的代码。

主要使用了一种NodeType的参数来包装Node节点和满二叉树时当前节点的序号num,然后判断节点序号是否与遍历的序号(即当前节点实际的序号)相同全部相同则返回true,只要有一个不同则返回false

以下为书上代码:

public boolean isCBT(Node head) {
    if (head == null) {
        return true;
    }
    Queue<Node> queue = new LinkedList<Node>();
    boolean leaf = false;
    Node l = null;
    Node r = null;
    queue.offer(head);
    while (!queue.isEmpty()) {
        head = queue.poll();
        l = head.left;
        r = head.right;
        if ((leaf && (l != null || r != null)) || (l == null && r != null)) {
            return false;
        }
        if (l != null) {
            queue.offer(l);
        }
        if (r != null) {
            queue.offer(r);
        } else {
            leaf = true;
        }
    }
    return true;
}

 

posted @   幻梦翱翔  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示
主题色彩