剑指 Offer 68 - II. 二叉树的最近公共祖先
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情。
1、题目📑
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
实例1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
实例2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
2、思路🧠
方法一:DFS 深度优先遍历
最近公共祖先的定义: 设节点 root 为节点 p, q 的某公共祖先,若其左子节点 root.left 和右子节点 root.right 都不是 p,q 的公共祖先,则称 root 是 “最近的公共祖先” 。
分析题目主要存在3种情况
- 节点p,节点q分别在根节点两侧
- 节点p,节点q都在根节点左侧
- 节点p,节点q都在根节点右侧
通过递归对二叉树进行先序遍历,当遇到节点 p 或 q 时返回。从底至顶回溯,当节点 p, q 在节点 root 的异侧时,节点 root 即为最近公共祖先,则向上返回 root 。
- 递归结束:
- 根节点为空
- 节点p、q为根节点
- 递归:
- 递归左子节点,即left
- 递归右子节点,即right
- 返回值:
- 当
left和right都为空时,左右子节点都不包括节点p、q,返回null - 当
left和right都不为空时,左右子节点都包括节点p、q,并且不在同一侧,返回根节点root - 当
left为空 ,right不为空 :p,q都不在root的左子树中,直接返回right。分为两种情况:- p,q 其中一个在
root的 右子树 中,此时right指向 p - p,q 两个节点在
root的 右子树 中,此时的right指向 最近公共祖先节点
- p,q 其中一个在
- 当
left不为空 ,right为空 :p,q都不在root的右子树中,直接返回left。分为两种情况:- p,q 其中一个在
root的 左子树 中,此时left指向 p - p,q 两个节点在
root的 左子树 中,此时的left指向 最近公共祖先节点
- p,q 其中一个在
- 当
废话少说~~~~~上代码!
3、代码👨💻
第一次commit AC
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || p == root || q == root) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p , q);
if(left == null && right == null) return null; //情况1
if(left == null) return right;//情况3
if(right == null) return left;//情况4
return root;//情况2
}
}
时间复杂度:O(N) N 为二叉树节点的个数
空间复杂度:O(N)
4、总结
该题目的是对树结构的理解与遍历,熟悉二叉树的递归套路,需要掌握先序、中序、后序的基本概念以及遍历。并且还要了解树的递归操作,以及每一步的具体流程。
树的先序、中序、后序模板:
package com.cz.Tree;
import java.util.Stack;
/**
* @ProjectName: Data_structure
* @Package: com.cz.Tree
* @ClassName: UnRecursiveTraversalTree
* @Author: 张晟睿
* @Date: 2022/3/20 16:06
* @Version: 1.0
*/
public class UnRecursiveTraversalTree {
public static void main(String[] args) {
Node1 head = new Node1(1);
head.left = new Node1(2);
head.right = new Node1(3);
head.left.left = new Node1(4);
head.left.right = new Node1(5);
head.right.left = new Node1(6);
head.right.right = new Node1(7);
pre(head);
System.out.println("========");
middle(head);
System.out.println("========");
post(head);
System.out.println("========");
}
public static class Node1 {
public int value;
public Node1 left;
public Node1 right;
public Node1(int val) {
value = val;
}
}
public static void pre(Node1 head) {
System.out.println("先序遍历:");
Stack<Node1> s = new Stack<>();
if(head != null) {
s.push(head);
while(!s.isEmpty()) {
Node1 node = s.pop();
System.out.print(node.value + " ");
if(node.right != null) s.push(node.right);
if(node.left != null) s.push(node.left);
}
}
System.out.println();
}
public static void middle(Node1 head){
System.out.println("中序遍历:");
if (head != null) {
Stack<Node1> s = new Stack<>();
while(!s.isEmpty() || head != null) {
//步骤1:如果头结点不为空的话,一直向左边执行
if (head != null) {
s.push(head);
head = head.left;
}else {//根节点打印后,来到右树,继续执行步骤1
head = s.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
System.out.println();
}
}
public static void post(Node1 head){
System.out.println("后序遍历:");
if(head != null) {
Stack<Node1> s = new Stack<>();
s.push(head);
Node1 c = null; //指向栈顶的某个元素的位置
while(!s.isEmpty()) {
c = s.peek();
//判断c左孩子 是否已经处理过
if(c.left != null && head != c.left && head != c.right) {
s.push(c.left);
//判断c右孩子 是否已经处理过
}else if(c.right != null && head != c.right) {
s.push(c.right);
}else {
System.out.print(s.pop().value+" ");
head = c; //head用来记录上次打印的内容
}
}
System.out.println();
}
}
}
❤️来自专栏《LeetCode基础算法题》欢迎订阅❤️
厂长写博客目的初衷很简单,希望大家在学习的过程中少走弯路,多学一些东西,对自己有帮助的留下你的赞赞👍或者关注➕都是对我最大的支持,你的关注和点赞给厂长每天更文的动力。
对文章其中一部分不理解,都可以评论区回复我,我们来一起讨论,共同学习,一起进步!
原题链接:剑指 Offer 68 - II. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)