110.平衡二叉树
递归——后序遍历(求高度)
1、明确参数值和返回值
2、明确终止条件
3、明确单层逻辑
平衡二叉树需要求左右子树的高度,从而获得高度差。
这里需要注意一下单层逻辑中:
1、当高度差符合平衡条件时,需要向上层返回本结点的高度,以供下一个结点判断是否平衡。
2、当高度差不符合平衡条件,需要返回一个标识值,说明它已经不是平衡二叉树了。
257. 二叉树的所有路径
递归——前序遍历(求深度)
不同于平衡二叉树通过结点高度来判断平衡,本题需要利用深度的逻辑,提起深度,只能是前序遍历。
1、明确参数值和返回值
参数:二叉树的根结点,一个保存临时结点List<Integer>类型的path数组,一个保存完整路径List<String>类型的result数组
2、明确终止条件
此次递归和之前的不同,递归终止在叶子结点,不再是空结点。
递归到叶子节点时,需要将此时的path数组中的结点,组成路径放入result数组。
3、明确单层逻辑
中:放入根节点
左:如果根节点的左孩子不为空,递归并回溯。
右:如果根节点的右孩子不为空,递归并回溯。
404.左叶子之和
递归——后序遍历
什么是左叶子:某结点的左孩子不为空,且左孩子的左孩子为空,左孩子的右孩子为空,则该结点的左孩子是左叶子结点。
1、明确参数值和返回值
返回值:int类型的左叶子之和。参数:根节点
2、明确终止条件
如果是空结点,返回0
如果是叶子结点,返回0
3、明确单层逻辑(我们要找叶子结点的父结点)
左:递归求左子树中的左叶子结点的值——leftCounts
再判断当前结点是否是左叶子结点的父结点,如果是左叶子的父结点,leftCounts赋值为左叶子的值;如果不是左叶子的父结点,跳过该if分支。
右:递归求右子树中的左叶子结点的值——leftCounts
中:sum=leftCounts+rightCounts
513.找树左下角的值
层序遍历——常规模板题
二刷可以练一下递归
112. 路径总和
遇到的问题:递归函数的布尔返回值不知道怎么写。
1、明确参数值和返回值
返回值:如果递归返回的是true,return true;其他情况返回false。
2、明确终止条件
叶子结点&&count == 0,返回true
叶子结点(count != 0),返回false
3、明确单层逻辑(我们要找叶子结点的父结点)
左:如果左孩子不为空,count—左孩子的val值,递归并回溯count。
右:如果右孩子不为空,count—右孩子的val值,递归并回溯count。
中:没有中结点的逻辑
113.路径总和ii
112. 路径总和 和 113. 路径总和ii 详细的讲解了递归函数什么时候需要返回值,什么不需要返回值。
本题需要遍历整个树,找到所有路径,所以递归函数不要返回值!
除此之外,就是设置一个List<Integer>类型的pathNode数组记录递归和回溯经过的结点,一个List<List<Integer>>类型的result数组记录找到的每一条符合条件路径。
tips:result.add( new ArrayList<>(pathNode) ); // 向result数组中添加整个pathNode数组
106.从中序与后序遍历序列构造二叉树
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素变为树结点。
如果后序数组中只有一个元素,返回该结点。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
根据第三步中找到的切割点,切割中序数组。
第五步:切割后序数组,切成后序左数组和后序右数组
中序数组大小一定是和后序数组的大小相同的
根据切割后的左中序数组的大小来确定切割后的左后序数组和右后序数组。
第六步:递归处理左区间和右区间
105.从前序与中序遍历序列构造二叉树
同上,后序换成前序
654.最大二叉树
思路和106. 105.一致,取最大值,切割数组,分别递归左数组和右数组。区间仍是左开右闭。
617.合并二叉树
递归:(前、中、后序都可以)只写了前序
合并二叉树需要遍历两棵树,和遍历一个树逻辑是一样的,只不过传入两个树的节点,同时操作。
确定终止条件时,有一点不同:
因为是传入了两个树,那么就有两个树遍历的节点t1 和 t2。
如果t1 == NULL 了,两个树合并就应该是 t2 了(如果t2也为NULL也无所谓,合并之后就是NULL)。
反过来如果t2 == NULL,那么两个数合并就是t1(如果t1也为NULL也无所谓,合并之后就是NULL)。
if (t1 == NULL) return t2; // 如果t1为空,合并之后就应该是t2 if (t2 == NULL) return t1; // 如果t2为空,合并之后就应该是t1
迭代:(层序遍历)
待刷
700.二叉搜索树中的搜索
递归:
常规题,明确三步走
迭代:二叉搜索树的迭代法十分简洁
这里阐述一下二叉搜索树的特性。
普通二叉树遍历的迭代法,需要使用栈来模拟深度遍历,使用队列来模拟广度遍历。对于一般二叉树,递归过程中还有回溯的过程,例如走一个左方向的分支走到头了,那么要调头,在走右分支。
对于二叉搜索树:
例如要搜索元素为3的节点, 我们不需要搜索其他节点,也不需要做回溯,查找的路径已经规划好了。由于其特殊性,也就是节点的有序性,可以不使用辅助栈或者队列就可以写出迭代法。而且对于二叉搜索树,不需要回溯的过程,因为节点的有序性就帮我们确定了搜索的方向。
中间节点如果大于3就向左走,如果小于3就向右走,如图:
98.验证二叉搜索树
利用二叉搜索树的特性: 遇到 搜索树,一定想着中序遍历,这样才能利用上特性
中序遍历二叉搜索树,得到的是一个有序数组。
通过判断这个数组是否有序,即可判断二叉树是否是二叉搜索树。
递归:
递归有坑,不幸掉坑里了。
TreeNode pre = null; //pre记录当前结点的前一个结点,即当前结点的左子树中的最大节点。
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
boolean left = isValidBST(root.left); //左
if (pre != null && pre.val >= root.val) return false;
pre = root;
boolean right = isValidBST(root.right);
return left && right;
}