【算法】二叉树的右视图
出处
letCode 299:https://leetcode-cn.com/problems/binary-tree-right-side-view/
题解地址可参考:https://leetcode-cn.com/problems/binary-tree-right-side-view/solution/er-cha-shu-de-you-shi-tu-by-leetcode-solution/
题目
给定一个二叉树的 根节点 root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
思路
深度优先搜索
我们对树进行深度优先搜索,在搜索过程中,我们总是先访问右子树。那么对于每一层来说,我们在这层见到的第一个结点一定是最右边的结点。这样一来,我们可以存储在每个深度访问的第一个结点,一旦我们知道了树的层数,就可以得到最终的结果数组。
广度优先搜索
我们可以对二叉树进行层次遍历,那么对于每层来说,最右边的结点一定是最后被遍历到的。
代码
二叉树的定义
首先要知道二叉树的定义,它的每个节点都包含一个左节点和右节点:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() { }
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
深度优先算法
1、定义一个HashMap,存放右视图下的节点
2、创建一个节点栈,存放当前遍历到的节点,并把根节点压入栈
3、创建一个深度栈,存放每个节点对应的深度,并把当前节点深度压入栈
4、遍历节点栈,对节点栈进行出栈操作
5、每次遍历,都取出节点栈和深度栈的栈顶元素
6、如果出栈的节点不为null,且HashMap中不存在对应深度的节点,就把该节点插入到HashMap中,然后继续将当前节点的左节点和右节点分别压入节点栈中,将depth + 1的值压入深度栈中
7、如果最终栈已经没有元素,则循环结束,然后将map中记录的每层的右节点转移到list上,并返回list
深度优先算法:
public List<Integer> rightSideView(TreeNode root) {
// 定义一个HashMap,存放右视图下的节点
Map<Integer, Integer> map = new HashMap<>();
// 定义一个节点栈,存放当前遍历到的节点
Deque<TreeNode> nodeStack = new ArrayDeque<>();
// 定义一个深度栈,存放每个节点对应的深度
Deque<Integer> depthStack = new ArrayDeque<>();
int maxDepth = -1;
// 节点栈先压入根节点
nodeStack.push(root);
// 深度栈压入
depthStack.push(0);
// 遍历节点栈
while (!nodeStack.isEmpty()) {
// 取出节点栈中的栈顶元素
TreeNode node = nodeStack.pop();
// 取出深度栈中的栈顶元素
int depth = depthStack.pop();
if (node != null) {
// 维护二叉树的最大深度
maxDepth = Math.max(maxDepth, depth);
// 如果不存在对应深度的节点,才把该节点插入到map中
if (!map.containsKey(depth)) {
map.put(depth, node.val);
}
// 将当前节点的左节点和右节点分别压入节点栈中
nodeStack.push(node.left);
nodeStack.push(node.right);
// 将depth + 1的值压入深度栈中
depthStack.push(depth + 1);
depthStack.push(depth + 1);
}
}
// 将map中记录的每层的右节点转移到list上
List<Integer> rightView = new ArrayList<>();
for (int d = 0; d <= maxDepth; d++) {
rightView.add(map.get(d));
}
// 返回这个list
return rightView;
}
广度优先算法
1、定义一个HashMap,存放右视图下的节点
2、创建一个节点队列,存放当前遍历到的节点,根节点先入队
3、创建一个深度队列,存放每个节点对应的深度,深度0先入队
4、遍历节点队列,对节点队列进行出队操作
5、每次遍历,都取出节点队列和深度队列的头部元素
6、如果出队的节点不为null,就把该节点插入到HashMap中,然后继续将当前节点的左节点和右节点分别入队,将depth + 1的值入队
7、如果最终队列已经没有元素,则循环结束,然后将map中记录的每层的右节点转移到list上,并返回list
广度优先算法:
public List<Integer> rightSideView(TreeNode root) {
// 创建一个HashMap, 存放右视图下的节点
Map<Integer, Integer> map = new HashMap<>();
// 创建一个节点队列,存放当前遍历到的节点
Queue<TreeNode> nodeQueue = new ArrayDeque<>();
// 创建一个深度队列,存放每个节点对应的深度
Queue<Integer> depthQueue = new ArrayDeque<>();
int maxDepth = -1;
// 节点队列:根节点先入队
nodeQueue.add(root);
// 深度队列:深度0先入队
depthQueue.add(0);
// 遍历节点队列
while (!nodeQueue.isEmpty()) {
// 取出节点队列的头部元素
TreeNode node = nodeQueue.remove();
// 取出深度队列的头部元素
int depth = depthQueue.remove();
// 如果头部节点不为nul
if (node != null) {
// 维护二叉树的最大深度
maxDepth = Math.max(maxDepth, depth);
// 由于每一层最后一个访问到的节点才是我们要的答案,因此不断更新对应深度的信息即可
map.put(depth, node.val);
// 将当前节点的左节点和右节点分别入节点队列
nodeQueue.add(node.left);
nodeQueue.add(node.right);
// 将depth + 1的值入深度队列两次
depthQueue.add(depth + 1);
depthQueue.add(depth + 1);
}
}
// 将map中记录的每层的右节点转移到list上
List<Integer> rightView = new ArrayList<Integer>();
for (int depth = 0; depth <= maxDepth; depth++) {
rightView.add(map.get(depth));
}
// 返回这个list
return rightView;
}