二叉树递归遍历
题目:144 145 94
- 先要解决的是递归问题,而递归本身也是一个难点,记住以下递归三要素,写递归按照这个写就行
- 确定递归函数的参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
- 然后题解照这个来就好,方法只负责把节点值加入到答案列表里,然后对节点继续延伸递归。所有 所有:节点 返回值:void
- 终止条件:节点为Null返回 该节点下面的递归完了返回
- 单层递归逻辑:把节点添加到答案列表里去,进行新的递归。不同顺序遍历,代码顺序不一样
二叉树的变代遍历
题目:仍然是 144 145 94,换一个方式就行
- 迭代会用到栈,不过递归的本质好像一种栈
- 递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数
- 这里的话,先序遍历和后序遍历思路相似,但是中序遍历就是特殊的了
- 这是因为前序遍历中访问节点(遍历节点)和处理节点(将元素放进result数组中)可以同步处理,但是中序就无法做到同步!
- 前序遍历:前序遍历顺序:中-左-右,入栈顺序:中-右-左
- 后序遍历:后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
- 中序遍历:很明显不一样,前面的都是每次把左右节点在一个阶段放进去,这个中序遍历是先把左边的都放进去,然后等到左边的都放完了,开始pop,然后在去找右节点。不清楚的话,可以画图模拟一下
while (cur != null || !stack.isEmpty()){
if (cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
二叉树的层序遍历
题目:102
- 涉及到层序遍历的,代码参考它即可
- 首先要知道,按照题目来说,得定义两种动态链表,一种的总的(resList)表示最终结果的答案,一种是里面包含每层的遍历结果(itemList)
- 递归方式:(深度遍历dfs
- 递归的参数和返回值:
public void checkFun01(TreeNode node, Integer deep)
2.确定终止条件:遍历到节点为null
3.单层递归逻辑:deep的存在是为了标记并判断目前遍历到的节点在第几层,还可以通过deep来确定resList的长度(如果resList的长度比deep短,就扩展一下resList的长度,并给它加一个itemList来存放当前层的结点)
- 接上面的单层递归逻辑,还要把目前遍历到的节点放到正确位置里,这里还可以利用deep
resList.get(deep - 1).add(node.val);
- 层序遍历也是讲究顺序的,从左到右,所以先把当前节点加进去,然后先递归node.left 再递归node.right
- 迭代方式:借助队列
- 需要一个队列来存放当前层的节点,同时把该层节点数记录下来
int len = que.size();
- 有了len之后,可以在把当前层的节点从队列里依次pop出来的同时也把其左右节点放进去。这样有利于分清,哪些节点是一个层的
while (len > 0) {
TreeNode tmpNode = que.poll();
itemList.add(tmpNode.val);
if (tmpNode.left != null) que.offer(tmpNode.left);
if (tmpNode.right != null) que.offer(tmpNode.right);
len--;
}
同类型题目:107
- 把102的最终结果反转一下即可
Collections.reverse(resList); - 顺便,到了自己写才发现,队列的定义是这样的,是LinkedList
Queue<TreeNode> que = new LinkedList<TreeNode>();
- 然后依然是很基础的问题,队列是用poll offer的
- 还有一种不用反转的方法,最后添加结果使用头插
ans.addFirst(temp);
同类型题目:199(二叉树右视图
-
简单来说,就是按层遍历,但是每次只取每一层的最后一个。判断一下长度然后取值就行,其他的不同大概就是只有一个动态数组就行了吧......
-
`if (len == 1) { resList.add(node.val); }`
同类型:637 二叉树的层平均值
- 按层遍历,顺便求个平均值
同类型:429
-
N叉树, 不再拘泥于左右节点,看题目里给的节点类,里面是孩子节点,所以本来对于添加左右节点的代码变成了以下内容
`List<Node> children = node.children; if (children == null || children.size() == 0) { continue; } for (Node child : children) { if (child != null) { que.offer(child); } }`
同类型:515
- 层遍历+找最大值
同类型:116
- 本题依然是层序遍历,只不过在单层遍历的时候记录一下本层的头部节点,然后在遍历的时候让前一个节点指向本节点就可以了
同类型:117
- 116是完全二叉树,117就是二叉树。甚至代码都一样......
同类型:求二叉树深度
- 最大深度:普通的层序遍历即可
- 最小深度:当出现第一个没有左右节点的节点时,就是最小深度
翻转二叉树
题目:226
- 翻转二叉树,仔细看下来,好像就是把左右节点都换一遍。只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果
- 递归:中序遍历是翻转两下,所以不用它
1.确定递归函数的参数和返回值:直接就用当前方法就行,一直递归到最下层
public TreeNode invertTree(TreeNode root)
2.退出条件:当节点为null 3.单层递归:
invertTree(root.left);//先对左子树进行节点交换
invertTree(root.right);//再对右子树进行节点交换
swapChildren(root);//把交换左右节点落实到行动中
return root;
-
额外再定义一个交换左右节点的函数
-
中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)
-
看迭代的话,可能会更明白?
-
迭代的话,感觉是层序遍历,但是每一层都要交换左右节点
while (!deque.isEmpty()) { int size = deque.size(); while (size-- > 0) { TreeNode node = deque.poll(); swap(node); if (node.left != null) { deque.offer(node.left); } if (node.right != null) { deque.offer(node.right); } } }