leetcode: Binary Tree Right Side View

从二叉树的右侧看这个二叉树,返回看到的最右侧的各个节点.....实际就是要求我们返回二叉树每一层的最右节点。

我的解法比较暴力,就是遍历整棵二叉树,返回最右节点...

具体实现上其实可以简化为只用一个数组动态记录每一层节点的情况并动态的讲最右节点的值add进去而不用记录整棵树的状态...

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> ret = new ArrayList<Integer>();
        TreeNode t = root;
        if(root == null)
        {
            return ret;
        }
        List<List<TreeNode>> q = new ArrayList<List<TreeNode>>();
        List<TreeNode> tmp = new ArrayList<TreeNode>();
        tmp.add(root);
        while(true)
        {
            if(tmp.size()==0)
            {
                break;
            }
            q.add(tmp);
            List<TreeNode> temp = new ArrayList<TreeNode>();
            for(TreeNode node : tmp)
            {
                if(node.right != null)
                {
                    temp.add(node.right);
                }
                if(node.left != null)
                {
                    temp.add(node.left);
                }
            }
            tmp = temp;
        }
        for(List<TreeNode> li : q)
        {
            ret.add(li.get(0).val);
        }
        return ret;
    }
}

<think>我们分析一下LeetCode 199题:二叉树的右视图。题目要求返回从右侧看二叉树时能看到的节点值(从上到下)。 给定的代码使用BFS(广度优先搜索)进行层序遍历,但做了一些调整。 代码: ans.append(q[0].val) 为什么这行代码能取出右节点的值? 解释: 在标准的BFS层序遍历中,我们通常按层处理节点,从左到右。但这里要求右视图,即每层最右边的节点。 然而,注意代码中处理节点的顺序: 1. 首先,将根节点加入队列。 2. 在每一层循环开始时,将队列中第一个节点的值(即q[0].val)加入结果列表ans。注意:此时队列中存放的是当前层的所有节点(实际上,在进入内层循环之前,队列中保存的是当前层的所有节点,且顺序是从左到右?但这里不是,因为入队顺序有调整)。 但是,观察内层循环中节点的入队顺序: if node.right: q.append(node.right) if node.left: q.append(node.left) 注意:这里先右子节点,后左子节点。这样,队列中下一层的节点顺序就是先右后左。 然而,我们是在内层循环开始之前取队列的第一个节点(q[0])的值。在进入内层循环处理当前层之前,队列中的节点是当前层的所有节点(按从左到右的顺序?)不对,因为我们在处理上一层时,将下一层的节点按从右到左的顺序入队了。 让我们重新梳理: 初始:队列q = [root] 第一层循环: ans.append(q[0].val) -> 取root的值(第一层只有一个节点) 然后进入内层循环(循环次数为当前队列长度1): 弹出节点root,然后先将其右子节点入队(如果存在),再将其左子节点入队(如果存在)。 假设root有左孩子和右孩子,那么入队顺序是:先右,后左。所以队列变成:[右, 左] 第二层循环: 队列q = [右, 左] ans.append(q[0].val) -> 取队列第一个节点(即右节点)的值,这就是第二层最右边的节点(因为这一层我们只看到右节点,左节点被右节点挡住了,所以右视图就是右节点)。 然后进入内层循环(循环次数为2): 先弹出右节点,然后将其右子节点入队(如果有),再将其左子节点入队(如果有)-> 假设右节点有孩子,则先入队右节点的右孩子,再入队右节点的左孩子。 然后弹出左节点,同样先入队左节点的右孩子,再入队左节点的左孩子。 注意:此时队列的顺序是:[右节点的右孩子, 右节点的左孩子, 左节点的右孩子, 左节点的左孩子] (因为入队顺序都是先右后左,且先处理右节点,所以右节点的孩子先入队) 第三层循环: 队列q = [右节点的右孩子, 右节点的左孩子, 左节点的右孩子, 左节点的左孩子] ans.append(q[0].val) -> 取队列第一个节点(即右节点的右孩子)的值。但是,第三层的最右节点应该是右节点的右孩子吗?实际上,在右视图中,第三层应该看到的是该层最右边的节点。而队列中第一个节点是右节点的右孩子,然后依次是右节点的左孩子、左节点的右孩子、左节点的左孩子。那么队列的第一个节点就是当前层最右边的节点吗? 为什么? 因为我们在处理上一层(第二层)时,将下一层(第三层)的节点按从右到左的顺序入队(先入队右节点的右孩子,再入队右节点的左孩子,然后左节点的右孩子,最后左节点的左孩子)。这样,在第三层循环开始时,队列的第一个节点就是第三层最右边的节点(即右节点的右孩子,如果存在的话,否则就是队列中第一个存在的节点?)。 但是,注意:我们每层只取队列的第一个节点(q[0].val),而队列中当前层的节点顺序是:从右到左(因为上一层节点出队时,先入队右孩子,再入队左孩子,并且上一层节点也是从右到左排列的,所以下一层节点入队后,队列中节点的顺序就是:上一层的右孩子的右孩子、上一层的右孩子的左孩子、上一层的左孩子的右孩子、上一层的左孩子的左孩子)。这样,队列的第一个节点就是当前层的最右节点。 因此,在每一层循环开始时,队列的第一个节点就是当前层的最右节点(因为队列中当前层的节点顺序是从右到左排列的,所以第一个节点是最右边的节点)。 为什么队列中当前层的节点顺序是从右到左? 因为: - 在上一层节点出队时,我们先处理上一层的节点(从右到左,因为上一层的节点在队列中也是从右到左排列的?),然后对于每个节点,我们先将其右孩子入队,再将其左孩子入队。 - 这样,下一层节点的入队顺序就是:先上一个节点的右孩子,再上一个节点的左孩子;然后下一个节点(也是上一层的节点,位于上一个节点的左边)的右孩子,再左孩子。所以整个下一层的节点在队列中是从右到左排列的。 因此,在每一层循环开始时,队列的第一个节点就是当前层最右边的节点,我们将其值加入结果列表。 总结:通过改变入队顺序(先右后左),使得每一层的节点在队列中从右到左排列,这样每层第一个节点就是最右节点。 注意:这种方法与常规的层序遍历不同,常规层序遍历每层是从左到右,而这里是从右到左。所以我们可以取每层的第一个节点作为右视图的节点。 但是,这个算法在每层循环中,内层循环会处理当前层的所有节点(从队列中弹出),并将下一层的节点按从右到左的顺序入队。这样,当内层循环结束后,队列中就是下一层的所有节点(从右到左)。然后下一层循环开始时,取队列第一个节点(即最右节点)的值。 因此,ans.append(q[0].val) 可以取出每层最右节点的值。 示例: 1 / \ 2 3 \ 4 右视图:[1,3,4] 执行过程: 初始:q = [1] -> 取1,然后入队顺序:先右子节点3,再左子节点2 -> q=[3,2] 下一层:取q[0]即3,然后处理节点3:先入队其右子节点(无),再入队左子节点(无);然后处理节点2:入队其右子节点4(没有左子节点)-> q=[4] 下一层:取q[0]即4 -> 结束。 所以结果ans=[1,3,4] 注意:如果每层第一个节点不存在(比如队列为空,但循环条件已经判断了q不为空,所以不会出现),所以安全。 但是,有没有可能某一层有多个节点,但最右边的节点并不是队列的第一个节点?不会,因为我们的入队顺序保证了每一层的节点在队列中是从右到左排列的。 因此,这个算法是正确的。 相关问题: §§相关问题§§: 1. 如果要求二叉树的左视图,应该如何修改这段代码? 2. 这段代码中,内层循环的节点处理顺序(先右子节点后左子节点)对结果有什么影响?如果交换顺序会怎样? 3. 除了BFS,还有哪些方法可以解决二叉树的右视图问题? 4. 如何用深度优先搜索(DFS)实现二叉树的右视图?</think># LeetCode 199题:二叉树的右视图解析 ## 问题解答 `ans.append(q[0].val)` 能够取出每层最右侧节点的值,是因为代码使用了**改进的BFS层序遍历**,通过特定的节点入队顺序,确保队列中每层的第一个节点始终是该层最右侧的节点。 ## 详细解释 ### 核心算法原理 这段代码实现了二叉树的**右视图**(从右侧看二叉树时能看到的节点)。关键点在于: 1. **使用队列进行BFS层序遍历** 2. **特殊的入队顺序:先右子节点,后左子节点** 3. **在每层循环开始时,队列的第一个节点就是该层最右侧的节点** ### 代码执行流程分析 假设二叉树结构: ``` 1 / \ 2 3 \ 4 ``` 右视图应为 `[1, 3, 4]` 执行步骤: 1. **初始状态**: - 队列 `q = [1]` - 结果 `ans = []` 2. **处理第一层**: - `ans.append(q[0].val)` → `ans = [1]` - 处理节点1: - 先入队右子节点3:`q.append(3)` - 再入队左子节点2:`q.append(2)` - 队列变为 `[3, 2]` 3. **处理第二层**: - `ans.append(q[0].val)` → `ans = [1, 3]` - 处理节点3(无子节点) - 处理节点2: - 入队右子节点4:`q.append(4)` - 队列变为 `[4]` 4. **处理第三层**: - `ans.append(q[0].val)` → `ans = [1, 3, 4]` - 处理节点4(无子节点) - 队列为空,结束 ### 为什么 `q[0]` 总是最右侧节点 1. **入队顺序**:总是先处理右子节点,再处理左子节点 ```python if node.right: q.append(node.right) # 先右 if node.left: q.append(node.left) # 后左 ``` 2. **队列特性**:先进先出(FIFO) 3. **结果**: - 每层节点入队顺序是**从右到左** - 队列中**第一个节点**总是该层**最右侧的节点** - 队列中**最后一个节点**总是该层**最左侧的节点** ### 关键代码分析 ```python while q: ans.append(q[0].val) # 队列第一个节点是当前层最右侧节点 for _ in range(len(q)): # 处理当前层所有节点 node = q.popleft() # 特别注意:先右后左的入队顺序 if node.right: q.append(node.right) if node.left: q.append(node.left) ``` ## 时间复杂度 - **O(n)**:每个节点恰好入队和出队一次 - **空间复杂度 O(n)**:队列最大空间为最宽层的节点数 ## 相关问题
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值