基础和技术就像无敌的深渊,小伙子,你要不断的学哟~~…
特此鸣谢在leetcode上分享答案的各位大神,让我能够对自己的笔记有如下补充:
先来上概念和技巧,以备不时之查:
用**数组实现的堆**就是树(堆就是一个完全二叉树,用数组来存储则不需要节点指针,一般也就是用数组来存储完全二叉树,不是完全二叉树的树不适合用数组存储)用链表实现就是常见的树有时候题目会要求咱们写出来的**算法的时间复杂度为O(nlogN)**,此时咱们就要能反应出来能搞出对数级别的时间复杂度的数据结构就那几个呀:
二分搜索二叉树相关的数据结构,TreeMap,PriorityQueue… 遇到求最值相关的题目咱们的解法大方向就是动态规划之类的去迭代求解,但是算法或者说函数中具体用的数据结构就是:
二叉堆。二叉堆实现的优先级队列取最值的时间复杂度为O(logN),但是二叉堆实现的优先级队列默认的顶上元素是最大值,所以一般咱们用来处理或者说删除最大值等平衡搜索二叉树。平衡二叉搜索树也可以求最值,也可以实现修改或者删除一个值,时间复杂度都是O(logN)
二叉查找树或者叫二叉搜索树:B+Tree是由平衡二叉树演变而来,而平衡二叉树是由二叉查找树演化而来,所以说B树肯定是一颗平衡二叉树和二叉搜索树,这里有包含关系呢;而平衡二叉树也是一颗二叉查找树
下来就是咱们的常见树题型喽:
二叉树(多叉树以及N叉树等)的题目常见的思路有:
递归(我先搞清楚当前根节点应该做什么,然后让子节点去模仿根节点进行前中后序的遍历就行,不断迭代)。而递归解法大概可以分为两类思路
遍历一遍二叉树就能得出答案(这也是回溯算法核心,回溯算法感觉本质上就是暴力遍历或者叫暴力穷举嘛)通过分解问题计算答案,感觉是不是有点像分治算法,或者归并排序(要对一个大东西排序,我先把这个大东西分为两半,然后先对左一半排好序,然后再对又一半排好序,最后把排好序的两半合并起来)。(所以说,有位大佬也说过,所有的回溯、动归、分治都是树的问题) BFS层级遍历
有时候也叫迭代方式,其实和咱们下面前中后序遍历一样,核心都是封装好一个函数呗,以备不时之调。
public void traverse(TreeNode root){
......
//先将root加入队列中
Queue queue = new linkedList<>();
queue.offer(root);//如果在不违反容量限制的情况下立即执行,则将指定的元素插入到此队列中。
//咱们一般碰到二叉树的最大深度、最小深度、层序遍历结果等问题,会想着构造一个depth或者size或者level等,来记录了当前遍历到的层数
int depth = 1;//或者叫int level = 1,都行,root这一层肯定就算是第一层了呗,所以这个代表层数的变量初始化为1
//while循环嵌套一个for循环,意思就是,while循环从root向最后一层走,指明了前进的方向,for循环利用queue.size()为限制下的i变量从左向右移动移动,指明了横溢的方向
while(!queue.isRmpty()){
......
for(int i = 0; i < queue.size(); i++){
//对左右节点逐个击破
if(queue.poll().left != null){//queue.poll()意思是检索并删除此队列的头,如果此队列为空,则返回 null 。
queue.offer(queue.poll().left);
}
if(queue.poll().right != null){
queue.offer(queue.poll().right);
}
}
depth++;
}
}
上点干活:
二叉树的前序遍历、中序遍历、后序遍历
class Solution {
//时间复杂度为O(n),n是二叉树节点的个数,每个节点会被访问一次且只会被访问一次;空间复杂度w取决于递归的深度,最坏情况下一条叉可以到O(n)
public List inorderTraversal(TreeNode root) {
List resultList = new ArrayList<>();
inorder(root, resultList);
return resultList;
}
//一般涉及到树的遍历,咱们就封装一个inorder呀、preorder呀、aferorder呀等三个前中后序b方法,以后不同的题目能复用呀,多好
public void inorder(TreeNode root, List list){
//官话判空
if(root == null){
return;
}
//inorder(root, ...)表示当前遍历到root节点,那么题目要求中序遍历的话就是左->根->右,所以就是先递归调用inorder(root.left)来遍历root节点的zuo'zi'shu左子树,然后将root的节点的值加入答案,最后再递归调用inorder(root.right, ...)来遍历root节点的右子树。最终写上递归终止条件w也就是碰到空节点停止递归就行
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
那这两道不就把咱们封装的函数改一下,再改一下调用那块就行了。这难道就是传说中的举一反三,哦,天呐
二叉树的层级遍历、最大深度、最小深度、节点个数、最短路径等(放到一块是因为如果我能够从上到下,从左到右把树遍历一边,那么我搞一个变量或者单列集合或者双列集合可以记录一下节点或者路径的相关信息,就有解题思路了)



