LeetCode题解之填充二叉树中每个节点的下一个右侧节点

完全二叉树的右侧节点

LeetCode原题链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/

给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
在这里插入图片描述

分析

由于这题处理的二叉树是一棵完全二叉树,所以递归处理的方式也比较简单。主要是使用了递归地自顶向下的处理方法。

自顶向下的分析思想:根据当前节点已有的信息寻找答案,如果需要传递给子节点参数信息,则将参数信息进行传递。

解题思路

  1. 确定递归条件:root为null或者当前节点没有left节点
  2. 将当前节点的左节点的next指针指向当前节点的右节点
  3. 如果当前节点有next指针,则把当前节点的右节点的next指针指向当前节点的next节点的左节点上

代码

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
        dfs(root);
        return root;
    }

    private void dfs(Node root) {
    	// 递归结束条件
        if (root == null || root.left == null) return;
        // 连接当前节点的左右节点
        root.left.next = root.right;
        // 处理当前节点的next指针
        if (root.next != null) {
            root.right.next = root.next.left;
        }
        // 递归处理左节点
        dfs(root.left);
        // 递归处理右节点
        dfs(root.right);
    }
}

非完全二叉树的右侧节点

LeetCode原题连接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/

在这里插入图片描述

分析

题目中所给的是一颗二叉树,单并没有说是一棵完全二叉树,所以节点对应的子树可能没有左子树或者没有右子树或者二者都没有。这时候我的思路就是使用递归并结合自顶向下的思想来解决。

好了,接下来看一下题的解题思路吧!

解题思路

首先确定递归条件:递归函数传入的是叶节点的孩子节点的时候结束递归
确定每个节点需要做的处理:
(1) 当前节点的左节点不为空时,将左节点的next指针指向当前节点的右节点(不需要考虑右节点是否为空);
(2) 如果当前节点的next值不为null,则需要先找到当前节点的最右侧节点R(右节点不为null的时候为右节点,否则为左节点),之后再找到第一个左右节点不全为null的节点,找出其子节点中最左的不为null的节点L,当节点R和和节点L都不为空的时候,将R的next设置为L
递归处理右子树
递归处理左子树

为什么先递归处理右子树?

答:因为再递归过程中,需要一直找到最右侧节点,所以必须保证右侧的next指针指向是正确的!

代码

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    private void dfs(Node root) {
        if (root == null) return;
        // 处理当前节点的左右节点
        if (root.left != null) {
            root.left.next = root.right;
        }
        // 处理next节点
        if (root.next != null) {
            Node leftNode = root.right != null ? root.right : root.left;
            Node rightRootNode = root.next;
            while(rightRootNode != null && rightRootNode.left == null && rightRootNode.right == null) {
                rightRootNode = rightRootNode.next;
            }
            if (leftNode != null && rightRootNode != null) {
                Node rightNode = rightRootNode.left != null ? rightRootNode.left : rightRootNode.right;
                leftNode.next = rightNode;
            }
        }
        // 先递归处理右节点:确保右子树的next指针正确构造
        dfs(root.right);
        dfs(root.left);
    }
    
    public Node connect(Node root) {
        dfs(root);
        return root;  
    }
}

总结

两种方法都使用了自顶向下的递归分析的思想,通过递归地处理当前节点来得到问题的答案。我觉得这种分析方法的核心在于:

  1. 确定递归条件(什么时候结束)
  2. 当前节点需要执行的操作(只考虑当前节点)

这也是递归处理的时候的两大难点,深入理解这两点还需要多做题啊!!

好了,今天就分享到这里了,欢迎大家给我留言哦!!

展开阅读全文
©️2020 CSDN 皮肤主题: 游动-白 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值