刷算法Leetcode---9(二叉树篇Ⅲ)

简介: 刷算法Leetcode---9(二叉树篇Ⅲ)

前言
本文是跟着代码随想录的二叉树顺序进行刷题并编写的 代码随想录

    二叉树的题目较多,就多分了几次写,这是第三篇

    这是力扣刷算法的其他文章链接:刷算法Leetcode文章汇总

二叉树篇Ⅲ
(1)226. 翻转二叉树
dfs,对每个节点反转左右子树

class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null)return null;
TreeNode left = invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left=right;
root.right=left;
return root;
}
}
(2)101. 对称二叉树
①dfs,左右子树同时递归并进行判断

class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return isSymmetricNode(root.left, root.right);
}
public boolean isSymmetricNode(TreeNode node1, TreeNode node2){
if(node1 == null && node2 == null) return true;
if(node1 == null || node2 == null) return false;
if(node1.val != node2.val) return false;
return isSymmetricNode(node1.left, node2.right)
&&isSymmetricNode(node1.right,node2.left);
}
}
②bfs+队列,左右比较节点依次入队。注意空节点也要加入队列,代表左右位置

    注意:ArrayDeque线程不安全不能加入空节点,因此使用LinkedList实现队列

class Solution {
private Deque queue;
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
queue = new LinkedList();
queue.addLast(root.left);
queue.addLast(root.right);
while(!queue.isEmpty()){
TreeNode node1 = queue.pollFirst(), node2 = queue.pollFirst();
if(node1 == null && node2 == null) continue;
if(node1 == null || node2 == null) return false;
if(node1.val != node2.val) return false;
queue.addLast(node1.left);
queue.addLast(node2.right);
queue.addLast(node1.right);
queue.addLast(node2.left);
}
return true;
}
}

(3)222. 完全二叉树的节点个数
①bfs+队列,同102题(可见上一篇),层序遍历计数即可

    ②dfs,同102题(可见上一篇),递归左右节点计数

    ③二分查找+位运算,使用二分查找确定分支,位运算选择左右节点。

    具体操作:先找最左节点确定层数level(根为第零层),总节点数min=1<<(level),max=((1<<(level+1))-1,在min和max中进行二分查找。若mid处的node空,取左半部分迭代,若node不空取右半部分迭代;确定level层某个节点是否存在:node从根开始,根据与half=1<<(level-1)进行位与,即从左第二位开始取,为0左移为1右移,循环half>>1,判断node是否空。

    特点:使用层数位的二进制可表示某一次的所有节点,位运算确定左右的选择,0左移1右移

class Solution {
public int countNodes(TreeNode root) {
if(root==null)return 0;
TreeNode node = root;
int level=0;
while(node.left!=null){
node=node.left;
level++;
}
int min = 1<0){
if((bits&mid)==0)node=node.left;
else node=node.right;
bits>>=1;
}
return node!=null;
}
}

(4)110. 平衡二叉树
①dfs自下而上,先判断左右子树,并将高度回溯,返回-1进行剪枝

class Solution {
public boolean isBalanced(TreeNode root) {
return getDepth(root)>=0;
}
private int getDepth(TreeNode node){
if(node==null) return 0;
int left = getDepth(node.left);
int right = getDepth(node.right);
if(left==-1||right==-1||Math.abs(left-right)>1)return -1;
return Math.max(left,right)+1;
}
}
②dfs自上而下,先计算根节点再判断左右子树

class Solution {
public boolean isBalanced(TreeNode root) {
if(root==null)return true;
return Math.abs(getDepth(root.left)-getDepth(root.right))<=1&&isBalanced(root.left)&&isBalanced(root.right);
}
private int getDepth(TreeNode node){
if(node==null) return 0;
return Math.max(getDepth(node.left),getDepth(node.right))+1;
}
}
(5)257. 二叉树的所有路径
①dfs,递归不空节点和已有路径,为叶子节点时记录结果

class Solution {
private List res;
public List binaryTreePaths(TreeNode root) {
res = new ArrayList<>();
if(root==null)return res;
dfs(root,Integer.toString(root.val));
return res;
}
private void dfs(TreeNode node,String s){
if(node.left==null&&node.right==null)res.add(s);
if(node.left!=null)dfs(node.left,s+"->"+Integer.toString(node.left.val));
if(node.right!=null)dfs(node.right,s+"->"+Integer.toString(node.right.val));
}
}
②bfs+队列,nodeQueue记录节点,pathQueue记录每个节点对应的路径,若为叶子节点则记录结果

class Solution {
private List res;
private Deque nodeQueue;
private Deque pathQueue;
public List binaryTreePaths(TreeNode root) {
res = new ArrayList<>();
if(root==null)return res;
nodeQueue = new ArrayDeque<>();
pathQueue = new ArrayDeque<>();
nodeQueue.addLast(root);
pathQueue.addLast(Integer.toString(root.val));
while(!nodeQueue.isEmpty()){
TreeNode tempNode = nodeQueue.pollFirst();
String tempPath = pathQueue.pollFirst();
if(tempNode.left==null&&tempNode.right==null)res.add(tempPath);
if(tempNode.left!=null){
nodeQueue.addLast(tempNode.left);
pathQueue.addLast(tempPath+"->"+Integer.toString(tempNode.left.val));
}
if(tempNode.right!=null){
nodeQueue.addLast(tempNode.right);
pathQueue.addLast(tempPath+"->"+Integer.toString(tempNode.right.val));
}
}
return res;
}
}

(6)404. 左叶子之和
①bfs+队列,同102题层序遍历(可看上一篇),记录每层第一个节点的和

    ②dfs,递归并记录是否为左孩子,若为左孩子并为叶子节点,则记录值

class Solution {
private int res;
public int sumOfLeftLeaves(TreeNode root) {
if(root==null)return 0;
res=0;
dfs(root,false);
return res;
}
private void dfs(TreeNode node, boolean isLeft){
if(isLeft&&node.left==null&&node.right==null){
res+=node.val;
return;
}
if(node.left!=null)dfs(node.left,true);
if(node.right!=null)dfs(node.right,false);
}
}

    ③dfs,有左孩子时判断左孩子是否为叶子节点,极简版

class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if(root==null)return 0;
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right)

    + (root.left!=null&&root.left.left==null&&root.left.right==null ? root.left.val : 0);
}

}
(7)513. 找树左下角的值
①bfs+队列,同102题层序遍历(可见上一篇),记录最新一层第一个节点的值。或者每层从右到左遍历,记录的最后一个节点即为结果

    ②dfs,递归每个节点的层数,并记录最底层的层数,遇到新层记录结果

class Solution {
private int maxDepth = 0, res = 0;
public int findBottomLeftValue(TreeNode root) {
dfs(root,1);
return res;
}
private void dfs(TreeNode node,int depth){
if(node==null)return;
if(depth>maxDepth){
res = node.val;
maxDepth = depth;
}
dfs(node.left,depth+1);
dfs(node.right,depth+1);
}
}

(8)112. 路径总和
①dfs,同257题,当为叶子节点且路径和满足时返回true

class Solution {
private int target;
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null)return false;
target = targetSum;
return dfs(root,0);
}
private boolean dfs(TreeNode node,int sum){
if(node==null)return false;
sum+=node.val;
if(node.left==null&&node.right==null&&sum==target)return true;
return dfs(node.left,sum)||dfs(node.right,sum);
}
}
②bfs+队列,同257题,nodeQueue记录节点,sumQueue记录节点对应的和,当取出的节点为叶子并且和为目标,返回true

    ③dfs,递归targetSum-root.val,若当前节点为叶子节点,则判断节点值是否与递归和相同

class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if(root==null)return false;
if(root.left==null&&root.right==null)return root.val==targetSum;
return hasPathSum(root.left,targetSum-root.val)||hasPathSum(root.right,targetSum-root.val);
}
}
二叉树篇Ⅲ总结
①bfs和dfs都可以很方便的遍历二叉树

    ②对于翻转二叉树、对称二叉树、平衡二叉树这种题,使用dfs非常方便

    ③dfs分为自下而上(从叶子到根)和自上而下(从根到叶子)两种,按题目需求选择,如110和112题

    ④对于222题的完全二叉树问题,使用二分法缩短查找时间,使用层数位二进制表示一层集结点,使用位运算确定一条到叶子节点的路径
相关文章
|
5天前
|
Go 开发者 索引
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣33 / 81/ 153/154)(Go语言版)
本文深入探讨了LeetCode中四道关于「搜索旋转排序数组」的经典题目,涵盖了无重复和有重复元素的情况。通过二分查找的变形应用,文章详细解析了每道题的解题思路和Go语言实现代码。关键点包括判断有序区间、处理重复元素以及如何缩小搜索范围。文章还总结了各题的异同,并推荐了类似题目,帮助读者全面掌握二分查找在旋转数组中的应用。无论是初学者还是有经验的开发者,都能从中获得实用的解题技巧和代码实现方法。
34 14
|
1月前
|
Go
【LeetCode 热题100】路径与祖先:二叉树中的深度追踪技巧(力扣437 / 236 )(Go语言版)
本文深入探讨二叉树中路径与祖先问题,涵盖两道经典题目:LeetCode 437(路径总和 III)和236(最近公共祖先)。对于路径总和 III,文章分析了双递归暴力解法与前缀和优化方法,后者通过哈希表记录路径和,将时间复杂度从O(n²)降至O(n)。在最近公共祖先问题中,采用后序遍历递归查找,利用“自底向上”的思路确定最近公共祖先节点。文中详细解析代码实现与核心要点,帮助读者掌握深度追踪技巧,理解树结构中路径与节点关系的本质。这类问题在面试中高频出现,掌握其解法意义重大。
54 4
|
1月前
|
算法 Go
【LeetCode 热题100】深入理解二叉树结构变化与路径特性(力扣104 / 226 / 114 / 543)(Go语言版)
本博客深入探讨二叉树的深度计算、结构变换与路径分析,涵盖四道经典题目:104(最大深度)、226(翻转二叉树)、114(展开为链表)和543(二叉树直径)。通过递归与遍历策略(前序、后序等),解析每题的核心思路与实现方法。结合代码示例(Go语言),帮助读者掌握二叉树相关算法的精髓。下一讲将聚焦二叉树构造问题,欢迎持续关注!
60 10
|
1月前
|
存储 算法 数据可视化
【二叉树遍历入门:从中序遍历到层序与右视图】【LeetCode 热题100】94:二叉树的中序遍历、102:二叉树的层序遍历、199:二叉树的右视图(详细解析)(Go语言版)
本文详细解析了二叉树的三种经典遍历方式:中序遍历(94题)、层序遍历(102题)和右视图(199题)。通过递归与迭代实现中序遍历,深入理解深度优先搜索(DFS);借助队列完成层序遍历和右视图,掌握广度优先搜索(BFS)。文章对比DFS与BFS的思维方式,总结不同遍历的应用场景,为后续构造树结构奠定基础。
136 10
|
1月前
|
Go 索引 Perl
【LeetCode 热题100】【二叉树构造题精讲:前序 + 中序建树 & 有序数组构造 BST】(详细解析)(Go语言版)
本文详细解析了二叉树构造的两类经典问题:通过前序与中序遍历重建二叉树(LeetCode 105),以及将有序数组转化为平衡二叉搜索树(BST,LeetCode 108)。文章从核心思路、递归解法到实现细节逐一拆解,强调通过索引控制子树范围以优化性能,并对比两题的不同构造逻辑。最后总结通用构造套路,提供进阶思考方向,帮助彻底掌握二叉树构造类题目。
120 9
|
2月前
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
78 9
 算法系列之数据结构-二叉树
|
4月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
154 2
|
5月前
|
存储 算法 Python
文件管理系统中基于 Python 语言的二叉树查找算法探秘
在数字化时代,文件管理系统至关重要。本文探讨了二叉树查找算法在文件管理中的应用,并通过Python代码展示了其实现过程。二叉树是一种非线性数据结构,每个节点最多有两个子节点。通过文件名的字典序构建和查找二叉树,能高效地管理和检索文件。相较于顺序查找,二叉树查找每次比较可排除一半子树,极大提升了查找效率,尤其适用于海量文件管理。Python代码示例包括定义节点类、插入和查找函数,展示了如何快速定位目标文件。二叉树查找算法为文件管理系统的优化提供了有效途径。
100 5
|
6月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
6月前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
157 5

热门文章

最新文章