深度优先遍历:
前序遍历:中左右(递归、迭代)
中序遍历:左中右(递归、迭代)
后序遍历:左右中(递归、迭代)
广度优先遍历:
层序遍历(迭代,使用queue)
2.递归遍历
前中后三种遍历,可以简单互换
3.迭代遍历
前序、后序两种可以简单互换(前序使用栈,后序在前序的基础上交换顺序+翻转即可)
中序(使用栈stack,因为处理的元素和访问的元素不是同一个,因此借助一个指针来实现☆)
5.层序遍历
使用队列queue,注意固定每一层需要循环的次数。
模板如下:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
vector<vector<int>> result;
while (!que.empty()) {
int size = que.size();
vector<int> vec;
// 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
vec.push_back(node->val);
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
result.push_back(vec);
}
return result;
}
};
6.翻转二叉树
使用后序、前序较为方便;
而使用中序遍历则需要注意左子树、中节点处理完之后,此时右子树是被处理过的刚刚的左子树,因此需继续处理左子树。
8.对称二叉树
不可简单的使用层序遍历,然后判断每一层是否为回文串这种方法。因为这样无法判断某些出现NULL时的情况。
递归方法!
先判断某些可以直接return false的情况,作为循环的结束出口(终止条件),
然后使用后序遍历(不严格)判断左右子树是否相等——判断外侧是否相等(left->left和right->right)+内侧是否相等(left->right和right->left)。
9.二叉树的最大深度
前序(中左右)可以求深度,后序(左右中)可以求高度。都是从1开始的。
采用递归的方法,判断那个子树的深度大,然后选择max加到根节点上,向上返回。
10.二叉树的最小深度
不可简单的将9中的max替换成min。因为这道题目对于最小深度的定义是叶子结点到根节点之间的最小距离。如果简单的将max替换为min,当根节点只有一个子树时,会出现深度为1的情况,无论另一个子树有多深。这显然是错误的。
我们需要添加判断条件,当某个节点左右子树均为NULL,此时才可以使用min.
否则需要添加存在子树的深度。
11.完全二叉树的节点个数
可以将所有节点遍历一遍,这样代码较为简单,但是缺点在于时间复杂度为o(n)。
如果使用了完全二叉树的特性,则不需要将所有节点都遍历一遍,时间复杂度会降低,但是代码较为复杂。
终止条件不太好写,可以再看看。
12.平衡二叉树
使用递归。
判断每个根节点的左右子树的深度之差是否超过1,是则返回false。
13.二叉树的所有路径
使用前序遍历。引用。
递归回溯。
to_string
再看看!
15.左叶子之和
后序遍历。
错了好几遍!因为太粗心,忘记加==号了
16.找树左下角的值
可以采用层序遍历法(迭代法),将最后一行的第一个输出即可,注意vector下标从0开始。
可以再看一下递归法,包含了递归回溯,掌握的不太好。
17.路径总和
递归法,前中后序都可以。
注意传参。
18.从中序与后序遍历序列构造二叉树
思路挺巧妙的,可以在练练。
前序、中序可以确定唯一的二叉树;
中序、后序也可以;
但前序+后序不可以,因为无法确定根节点,即无法将左右子树分开。
注意:切割后序时,此时数组中没有根节点,因此不需要+1.(我犯错了)
19.最大二叉树
和上面那个题目的思路完全相同,直接秒掉,一次通过。
同时,看视频学的新方法为:
21.合并二叉树
递归+前序遍历(中、后也可以);
很好!
22.二叉搜索树中的搜索
迭代与递归都比较简单,主要考察的是二叉搜索树的特性。
23.验证二叉搜索树
可以将树通过中序遍历转化为一个数组,然后判断该数组是否为单调递增的。(但是这样有点麻烦)
也可以直接判断,可以使用递归完成,并且可以添加双指针进行优化。
24.二叉搜索树的最小绝对差
和上面的题目思路相似,自己一次通过。没看视频
25.二叉搜索树的众数
注意==别写成=了!!
递归,一次遍历即可找出众数。
注意众数不一定只有一个,频率最高的都是众数(频率相等且最高)。
如果是普通二叉树,则先将树转化为map,然后对map的value进行排序(将map转化为pair形式的vector),然后输出前几个频率相同的数。 这里面涉及到好多个小知识点,一定要看看!
26.二叉树的最近公共祖先
写起来倒是不太难,但是这个思路还需要再看看。
不为空则向上传,代表该子树下有目标。
28.二叉搜索树的最近公共祖先
可以使用和16中一模一样的代码。但此时没有用到二叉搜索树的特性。
使用特性之后代码变得非常巧妙,看看。
本题的遍历顺序无所谓,因为不涉及中间节点的处理,只需要处理左右两个节点即可。
如何使用二叉搜索树的特性:按顺序搜索,第一次当p、q分别在某个节点的左右子树中,则该节点为最近的公共祖先。
29.二叉搜索树的插入操作
要重新写一下,自己写了好几次,总是不能全部通过。
递归比较简单,重点看递归
自己一直在写迭代,老是出错。
之后有空了写写迭代。
30.删除二叉搜索树中的节点
分五种情况处理,思路比较难想,不过操作并不难。
wocao!!! 我纯纯放屁,不难个der.抄都抄不对!
务必在好好写写!
注意删除之后需要手动释放内存。(这个操作好好学学)
如果是删除普通二叉树中的值,先查找目标值位置,然后将目标点与其右子树的最左边的叶子结点交换数值,然后继续遍历。当再次遍历到目标值时,其已经为叶子结点,直接进行删除即可。(思路极其巧妙,有趣)
31.修建二叉搜索树
代码不难,但是思路不好想,
建议再想想思路。
32.将有序数组转换为二叉搜索树
和18、19比较相似,一次通过。
33.把二叉搜索树转化为累加树
使用双指针!
记录前一个节点的数值是多少,然后采用倒过来的中序遍历,即右中左。
没掌握再看看TT.
代码还是比较简单的。