二叉树算法—广度搜索算法使用以及变形
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树算法—广度搜索算法使用以及变形相关的知识,希望对你有一定的参考价值。
参考技术A使用迭代来实现广度搜索
思索下面几个算法题:
102. 二叉树的层序遍历
429. N 叉树的层序遍历
107. 二叉树的层序遍历 II
101. 对称二叉树
广度搜索:即在水平维度一层层的去解析二叉树节点。即节点先进先出(队列结构)。
最简单的算法如上所示。
看到这个题,就想到了广度搜索算法。
难点: 如何将每一层的节点均存储到一个集合中?
开始想到的思路是: 每一层末尾节点后加一个标识位表示分层?但是这种思路是不太好的!
那如何实现分层存储?
思路 :首先广度搜索需要有一个大循环来遍历树,在大循环内部可不可以使用内层循环来遍历层呢? 即大循环开启的是每层的查询,小循环开启的是每层节点的查询?
难点 :如何控制内循环的循环次数?
思路 :每遍历一个节点,会将节点所以子节点存储到队列中。当遍历完一次,结束内循环时,队列里面存储的均是下一层的节点, 而队列的大小就是内循环的次数。
这个题如何使用广度搜索来实现?
说实话我是没有思路的,可能是广度遍历二叉树对我影响太深,以至于广度搜索和核心我到现在都没明白。
这个题的难点在于:如何比较最左和最右两个节点是否相等。
而本题的思想是两个节点的比较,那么在循环开始前,将root的左右节点放入到队列中,开启循环后,在队列中取出两个节点进行比较,若两个节点相等, 按照顺序,将最左和最右两个节点在次放入到队列中。
每次取出来的两个节点是有序的(最左和最右)
算法 | 二叉树的堂兄弟节点
前言
要想判断两个节点 x 和 y 是否为堂兄弟节点,我们就需要求出这两个节点分别的「深度」以及「父节点」。
因此,我们可以从根节点开始,对树进行一次遍历,在遍历的过程中维护「深度」以及「父节点」这两个信息。当我们遍历到 x 或 y 节点时,就将信息记录下来;当这两个节点都遍历完成了以后,我们就可以退出遍历的过程,判断它们是否为堂兄弟节点了。
常见的遍历方法有两种:深度优先搜索和广度优先搜索。
方法一:深度优先搜索
思路与算法
我们只需要在深度优先搜索的递归函数中增加表示「深度」以及「父节点」的两个参数即可。
代码
class Solution {
// x 的信息
int x;
TreeNode xParent;
int xDepth;
boolean xFound = false;
// y 的信息
int y;
TreeNode yParent;
int yDepth;
boolean yFound = false;
public boolean isCousins(TreeNode root, int x, int y) {
this.x = x;
this.y = y;
dfs(root, 0, null);
return xDepth == yDepth && xParent != yParent;
}
public void dfs(TreeNode node, int depth, TreeNode parent) {
if (node == null) {
return;
}
if (node.val == x) {
xParent = parent;
xDepth = depth;
xFound = true;
} else if (node.val == y) {
yParent = parent;
yDepth = depth;
yFound = true;
}
// 如果两个节点都找到了,就可以提前退出遍历
// 即使不提前退出,对最坏情况下的时间复杂度也不会有影响
if (xFound && yFound) {
return;
}
dfs(node.left, depth + 1, node);
if (xFound && yFound) {
return;
}
dfs(node.right, depth + 1, node);
}
}
复杂度分析
时间复杂度:O(n)O(n),其中 n 是树中的节点个数。在最坏情况下,我们需要遍历整棵树,时间复杂度为 O(n)O(n)。
空间复杂度:O(n)O(n),即为深度优先搜索的过程中需要使用的栈空间。在最坏情况下,树呈现链状结构,递归的深度为 O(n)O(n)。
方法二:广度优先搜索
思路与算法
在广度优先搜索的过程中,每当我们从队首取出一个节点,它就会作为「父节点」,将最多两个子节点放入队尾。因此,除了节点以外,我们只需要在队列中额外存储「深度」的信息即可。
代码
class Solution {
// x 的信息
int x;
TreeNode xParent;
int xDepth;
boolean xFound = false;
// y 的信息
int y;
TreeNode yParent;
int yDepth;
boolean yFound = false;
public boolean isCousins(TreeNode root, int x, int y) {
this.x = x;
this.y = y;
Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
Queue<Integer> depthQueue = new LinkedList<Integer>();
nodeQueue.offer(root);
depthQueue.offer(0);
update(root, null, 0);
while (!nodeQueue.isEmpty()) {
TreeNode node = nodeQueue.poll();
int depth = depthQueue.poll();
if (node.left != null) {
nodeQueue.offer(node.left);
depthQueue.offer(depth + 1);
update(node.left, node, depth + 1);
}
if (node.right != null) {
nodeQueue.offer(node.right);
depthQueue.offer(depth + 1);
update(node.right, node, depth + 1);
}
if (xFound && yFound) {
break;
}
}
return xDepth == yDepth && xParent != yParent;
}
// 用来判断是否遍历到 x 或 y 的辅助函数
public void update(TreeNode node, TreeNode parent, int depth) {
if (node.val == x) {
xParent = parent;
xDepth = depth;
xFound = true;
} else if (node.val == y) {
yParent = parent;
yDepth = depth;
yFound = true;
}
}
}
复杂度分析
时间复杂度:O(n)O(n),其中 n 是树中的节点个数。在最坏情况下,我们需要遍历整棵树,时间复杂度为 O(n)O(n)。
空间复杂度:O(n)O(n),即为广度优先搜索的过程中需要使用的队列空间。
以上是关于二叉树算法—广度搜索算法使用以及变形的主要内容,如果未能解决你的问题,请参考以下文章