二叉树算法—广度搜索算法使用以及变形

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),即为广度优先搜索的过程中需要使用的队列空间。





以上是关于二叉树算法—广度搜索算法使用以及变形的主要内容,如果未能解决你的问题,请参考以下文章

DFS-深度优先搜索与BFS-广度优先搜索

你知道吗?广度优先与深度优先只有这一个区别!

你知道吗?广度优先与深度优先只有这一个区别!

几道和「广度优先搜索」有关的算法面试题

常见搜索算法:深度优先和广度优先搜索

常见搜索算法:深度优先和广度优先搜索