二叉树的练习题(下)

1. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先

题目解析:

题目:

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

最近公共祖先的意思就是,找到他们俩个指定结点的相交结点

我们分为这四种情况:

1. root就是q/p的其中一个,那么root就是最近公共祖先

2. 如果p和q分布在root俩侧 那么root就是最近公共祖先

3. 如果p和q在同一侧, root先碰到谁,谁就是最近公共祖先

4. 在3的基础上如果p,q在同一层,那么root就是最近公共祖先

具体我举了个例子来看递归的情况,有需要的可以看看

此时这里后面有一部分代码是可以这么合并

我们还有另外一种写法,也就是之前求链表的时候,链表分叉了我们找到分叉的交点.

我们使用俩个栈来保存经过p,q的路径上的结点,然后我们计算俩个栈的大小,让大的那个栈先出多余的元素,当俩个栈的大小一致的时候,我们就同时出栈,直到出来的俩个元素相等为止.(该方法多练,不太熟)

1> 获取p,q的路径栈

2> 出栈多的元素

3> 同时出栈元素,直到出栈的元素一样

具体代码:

 public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
        //如果root是空,那么就没有公共结点,返回Null
            if(root == null) {
                return null;
            }
        //如果root就是p,q中的一个,返回root
            if(p == root || q == root) {
                return root;
            }
        //获取左右子树
            TreeNode leftTree = lowestCommonAncestor(root.left,p,q);
            TreeNode rightTree = lowestCommonAncestor(root.right,p,q);
        //如果左右子树都不为空,说明p,q分别分布在左右子树上
            if(leftTree != null && rightTree != null) {
                return root;
            }
        //左子树为空,那么都在右子树上
            if(leftTree == null && rightTree != null) {
                return rightTree;
            }
        //右子树为空,那么都在左子树上
            if(leftTree != null && rightTree == null){
                return leftTree;
            }
            return null;
        }

法2的具体代码:
 

public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
     
(1)非递归定义 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的根(root)结点。 ② 除结点外n0 , 其余的每一个结点都有且仅有一个直接前驱结点;有零个或多个直接后继结点。 (2)递归定义 一颗大树分成几个大的分枝,每个大分枝再分成几个小分枝,小分枝再分成更小的分枝,… ,每个分枝也都是一颗树,由此我们可以给出树的递归定义。 树(tree)是由n(n≥0)个结点组成的有限集合。n=0的树称为空树;n>0的树T: ① 有且仅有一个结点n0,它没有前驱结点,只有后继结点。n0称作树的根(root)结点。 ② 除根结点之外的其他结点分为m(m≥0)个互不相交的集合T0,T1,…,Tm-1,其中每个集合Ti(0≤i<m)本身又是一棵树,称为根的子树(subtree)。 2、掌握树的各种术语: (1) 父母、孩子与兄弟结点 (2) 度 (3) 结点层次、树的高度 (4) 边、路径 (5) 无序树、有序树 (6) 森林 3、二叉树的定义 二叉树(binary tree)是由n(n≥0)个结点组成的有限集合,此集合或者为空,或者由一个根结点加上两棵分别称为左、右子树的,互不相交的二叉树组成。 二叉树可以为空集,因此根可以有空的左子树或者右子树,亦或者左、右子树皆为空。 4、掌握二叉树的五个性质 5、二叉树的二叉链表存储。
### 关于线索二叉树练习题 #### 中序线索二叉树的特点 中序线索二叉树通过在每个节点增加两个指针域 `ltag` 和 `rtag` 来实现,分别表示该节点是否有前驱和后继。如果某个节点有左孩子,则它的 `lchild` 指向左孩子;如果没有左孩子,则指向其前驱节点。同样地,如果有右孩子,则 `rchild` 指向右孩子;如果没有右孩子,则指向其后继节点[^2]。 #### 寻找特定节点的前驱与后继 在一个中序线索二叉树中,对于任意节点 X 的前驱可以通过以下方式找到: - 如果节点 X 存在左子树,则前驱为左子树中的最右侧节点(即沿着左子树一直往右走直到无法再继续)。 - 若不存在左子树,则前驱为其父节点链上的最近祖先节点,且该祖先节点的右子树包含当前节点[^5]。 #### 构造一棵二叉树并对其进行线索化处理 假设已知某棵二叉树的先序遍历序列 `[A, B, D, E, C, F]` 及其中序遍历序列 `[D, B, E, A, C, F]`,则可以根据这些信息重建原始二叉树,并进一步将其转化为中序线索二叉树[^4]。 以下是基于 Python 实现的一个简单例子来展示如何构建这样的二叉树以及完成中序线索化的操作: ```python class TreeNode: def __init__(self, val=0, lchild=None, rchild=None, ltag=False, rtag=False): self.val = val self.lchild = lchild self.rchild = rchild self.ltag = ltag self.rtag = rtag def build_tree(preorder, inorder): if not preorder or not inorder: return None root_val = preorder[0] root_index_in_inorder = inorder.index(root_val) left_inorder = inorder[:root_index_in_inorder] right_inorder = inorder[root_index_in_inorder + 1:] left_preorder = preorder[1:len(left_inorder)+1] right_preorder = preorder[len(left_inorder)+1:] node = TreeNode(val=root_val) node.lchild = build_tree(left_preorder, left_inorder) node.rchild = build_tree(right_preorder, right_inorder) return node def threaded_binary_tree(root): pre_node = None def thread(node): nonlocal pre_node if not node: return thread(node.lchild) if not node.lchild: node.lchild = pre_node node.ltag = True if pre_node and not pre_node.rchild: pre_node.rchild = node pre_node.rtag = True pre_node = node thread(node.rchild) thread(root) # Example Usage preorder = ['A', 'B', 'D', 'E', 'C', 'F'] inorder = ['D', 'B', 'E', 'A', 'C', 'F'] tree_root = build_tree(preorder, inorder) threaded_binary_tree(tree_root) ``` 上述代码展示了如何利用给定的先序和中序遍历来创建一颗完整的二叉树,并对该二叉树执行中序线索化过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值