首页 > 编程知识 正文

递归实现二叉树,二叉树递归遍历概念

时间:2023-05-06 20:46:31 阅读:254975 作者:4412

Leetcode中的递归的问题总是很头疼,特别对于二叉树问题,因为二叉树是左右子树的形式,天生就具有递归性。在这篇文章中,系统总结一套解决递归问题的模版思路与解法,以后使用这个思路可以秒解很多二叉树的递归问题。

递归解题三部曲

何为递归?程序反复调用自身即是递归。

我自己在刚开始解决递归问题的时候,总是会去纠结这一层函数做了什么,它调用自身后的下一层函数又做了什么…然后就会觉得实现一个递归解法十分复杂,根本就无从下手。

相信很多初学者和我一样,这是一个思维误区,一定要走出来。既然递归是一个反复调用自身的过程,这就说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。

记住:千万不要去纠结每一级调用和返回的细节。

如上图所示,我们需要关心的主要是以下三点:

1)整个递归的终止条件。

2)一级递归需要做什么?

3)应该返回给上一级的返回值是什么?

因此,也就有了我们解Binary Tree递归题的三部曲

1)找整个递归的终止条件:递归应该在什么时候结束?

2)找返回值:应该给上一级返回什么信息?

3)本级递归应该做什么:在这一级递归中,应该完成什么任务?

一定要理解这3步,这就是以后秒杀递归算法题的依据和思路。

注意左右子树的递归,当前级就是右侧这种结构:

最后得到的代码如下:

class Solution { public int maxDepth(TreeNode root) { return root == null ? 0 : Math.max(maxDepth(root.left), maxDepth(root.right)) + 1; }}

 

https://leetcode.com/problems/count-complete-tree-nodes/

这道题按照上面的递归三部曲来做,不考虑是一颗完全二叉树。很简单可以得到一个初步的解答:

public int countNodes(TreeNode root) { // o(n)时间复杂度 if (root == null) return 0; int left = countNodes(root.left); int right = countNodes(root.right); return left + right + 1;}

如果考虑到是一颗完全二叉树,而我们知道,满二叉树的节点数和高度的计算公式是:

N = 2 ^ h – 1 (h 从1开始,根节点是1.)

       所以对于一颗完全二叉树,如果它的一个节点的左子树的高度 == 右子树的高度,那么就可以使用该公式直接计算节点数量,如果不相等,才使用上面的方法,递归遍历每一个节点,将数量增加。这样得到的代码如下:

public int countNodes(TreeNode root) { int left_h = 0, right_h = 0; TreeNode left = root, right = root; while(left != null) { left_h++; left = left.left; } while(right != null) { right_h++; right = right.right; } if (right_h == left_h) { return (int) Math.pow(2, left_h) - 1; // 满二叉树的节点个数是2 ^h - 1(h为高度) } return countNodes(root.left) + countNodes(root.right) + 1; }

对于这个算法的复杂度,leetcode评论中有人给出:

Since I halve the tree in every recursive step, I have O(log(n)) steps. Finding a height costs O(log(n)). So overall O(log(n)^2).

https://leetcode.com/problems/flatten-binary-tree-to-linked-list/

这道题,我们也是采用上面的三部递归,在构思的时候,考虑到divid and conquer的思想,当我们递归调用root的left和right后,可以认为left和right都已经flatten到位了,所以我们要做的,是在conquer的时候将root, 已经flatten的left和right树连接起来。具体的实现看代码:

public void flatten(TreeNode root) { if (root == null) return; flatten(root.left); flatten(root.right); // 先对左右子树调用flatten()函数,则表示此时左、右子树已经做好了flatten操作 // 将root, root.left, root.right 连成一个link list /* 1 l / r (2->3>4) (5->6) */ TreeNode right = root.right; TreeNode left = root.left; if (right == null) { // 右子树为空,直接将root连上左子树 root.right = left; root.left = null; return; } if (left == null) { // 左子树为空,直接返回 return; } while(left.right != null) { // 左右子树都不为空,找到left的最后一个节点,将其和right子树连起来 left = left.right; } left.right = right; root.right = root.left; root.left = null; }

该文主要参考了该篇博文:https://www.jianshu.com/p/1395fae8a1ae

具体的题目可以查看leetcode的二叉树tag: https://leetcode.com/tag/binary-tree/

解决的题目见https://leetcode.com/list/ 的Binary Tree(BFS/DFS)的收藏页。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。