阅读 149

高频算法面试题(三十三)- 输出二叉树的右视图

题目描述

给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值

示例

示例 1

1.png

输入: [1,2,3,null,5,null,4]
输出: [1,3,4]复制代码

示例 2

输入: [1,null,3]
输出: [1,3]复制代码

示例 3

输入: []
输出: []复制代码

提示:

  • 二叉树的节点个数的范围是 [0,100]

  • 100 <= Node.val <= 100

解题

解法一:深度优先搜索

思路

本题最容易想到的思路就是,如果我能遍历每一层,然后输出每一层的最右边的结点就可以了。我们知道,二叉树的层序遍历,需要借助队列来实现。实现的过程中发现,我们没法记录队列中的结点当前属于哪一层,因此这个方法其实是行不通的

那换一种思路,用深度优先搜索,如果对于树的每一层,我都先访问它的右子树,那么每一层我们访问到的第一个节点,一定是最右边的那个节点(假设右节点是存在的)

深度优先搜索:随意选择一个岔路口来走,走着走着发现走不通的时候,就回退到上一个岔路口,重新选择一条路继续走,直到走完所有的情况

通过上边的方式,我们就可以记录每一层访问的第一个节点,等搜索完所有的层,就得到了我们想要的结果(深度优先搜索,我们通常是用栈来实现)。你可能有个思路,但是并不是很明白,画图是最好的方式,用图来展示整个过程

2.png

有了思路,代码还算比较好写,需要借助两个栈

nodeStack:用来记录每次遍历到的节点(入栈的时候,右子树后进,这样访问栈的时候,每一层第一个出来的,一定是右子树(假设右子树存在)) depthStack:记录树的深度,目的是为了知道,每一层是否已经有我们需要的结点了,如果已经有了,该层的剩余结点就不需要了

代码

//输出二叉树的右视图
//深度优先搜索实现
func rightSideView(root *TreeNode) []int {
	rightViewMap := map[int]int{} //记录每一层第一个访问到的节点值(用map是为了知道每一层是否已经有访问过的结点)
	rightView := []int{} //最终存右视图结果的
	nodeStack := []*TreeNode{}
	depthStack := []int{}
	maxDepth := -1 //记录最大深度是为了最后变量右视图

	nodeStack = append(nodeStack, root) //根节点入栈
	depthStack = append(depthStack, 0) //跟结点属于第0层
	for len(nodeStack) != 0 {
		node := nodeStack[len(nodeStack)-1] //取出栈顶元素
		nodeStack = nodeStack[:len(nodeStack)-1]

		currDepth := depthStack[len(depthStack)-1] //当前节点属于哪一层
		depthStack = depthStack[:len(depthStack)-1]

		if node != nil {
			//维护二叉树的最大深度
			if currDepth > maxDepth {
				maxDepth = currDepth
			}
			
			//判断当前层,是否已经有节点被记录了.如果没有,才记录下来
			if _, ok := rightViewMap[currDepth];!ok {
				rightViewMap[currDepth] = node.Val
			}

			nodeStack = append(nodeStack, node.Left)
			nodeStack = append(nodeStack, node.Right)//右节点后入栈(后进先出)
			depthStack = append(depthStack, currDepth+1) //新进入的这两个结点的层数是相同的
			depthStack = append(depthStack, currDepth+1)
		}
	}
	for i:=0; i <= maxDepth; i++ {
		rightView = append(rightView, rightViewMap[i])
	}

	return rightView
}复制代码

解法二:广度优先搜索

思路

广度优先搜索:是一种“地毯式”层层推进的搜索策略,即先查找离起始顶点最近的,然后是次近的,依次往外搜索

如果理解了上边的深度优先的解法,用广度优先来解决就很简单了。我首先知道的是,用广度优先搜索,需要借助队列来实现,队列的夜店是先进先出,所以我们在搜索树的时候,可以让左子树先进队列,右子树后进,这样我们在访问每一层的结点的时候,不断更新我们需要的值,每一层最后一个访问到的,一定就是右子树

3.png思路和上边一样,需要维护两个队列,一个记录结点,一个记录层。如果你看懂了上边的代码,下边这个代码,一看就明白

代码

func rightSideView2(root *TreeNode) []int {
	if root == nil {
		return []int{}
	}
	rightViewMap := map[int]int{}
	rightView := []int{}
	maxDepth := 0

	nodeQueue := []*TreeNode{root}
	depthQueue := []int{}
	depthQueue = append(depthQueue, 0)

	for len(nodeQueue) != 0 {
		node := nodeQueue[0]
		if len(nodeQueue) <= 1 {
			nodeQueue = []*TreeNode{}
		} else {
			nodeQueue = nodeQueue[1:]
		}

		currDepth := depthQueue[0]
		if len(depthQueue) <= 1 {
			depthQueue = []int{}
		} else {
			depthQueue = depthQueue[1:]
		}

		if node != nil {
			if currDepth > maxDepth {
				maxDepth = currDepth
			}
			rightViewMap[currDepth] = node.Val

			nodeQueue = append(nodeQueue, node.Left)
			nodeQueue = append(nodeQueue, node.Right)
			depthQueue = append(depthQueue, currDepth+1)
			depthQueue = append(depthQueue, currDepth+1)
		}
	}

	for i := 0; i <= maxDepth; i++ {
		rightView = append(rightView, rightViewMap[i])
	}

	return rightView
}


作者:书旅
链接:https://juejin.cn/post/7031729980413313032

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐