[豪の算法奇妙冒险] 代码随想录算法训练营第十三天 | 递归遍历、迭代遍历、统一迭代、层序遍历
代码随想录算法训练营第十三天 | 递归遍历、迭代遍历、统一迭代、层序遍历
递归遍历
文章讲解:https://programmercarl.com/二叉树的递归遍历.html
视频讲解:https://www.bilibili.com/video/BV1Wh411S7xt/?vd_source=b989f2b109eb3b17e8178154a7de7a51
递归算法三要素
- 确定递归函数的参数和返回值:确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数,并且还要明确每次递归的返回值是什么,进而确定递归函数的返回类型
- 确定终止条件:写完递归算法,运行的时候,经常会遇到栈溢出的错误,其实就是没写终止条件或者终止条件写的不对。操作系统是用一个栈的结构来保存每一层递归的信息,如果递归没有正确终止,操作系统的内存栈必然就会溢出
- 确定单层递归的逻辑:确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程
LeetCode144 二叉树的前序遍历
题目链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/description/

class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preOrder(result, root);
return result;
}
public void preOrder(List<Integer> result, TreeNode root){
if(root == null){
return;
}
result.add(root.val);
preOrder(result, root.left);
preOrder(result, root.right);
}
}
LeetCode145 二叉树的后序遍历
题目链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/description/

class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
postOrder(result, root);
return result;
}
public void postOrder(List<Integer> result, TreeNode root){
if(root == null){
return;
}
postOrder(result, root.left);
postOrder(result, root.right);
result.add(root.val);
}
}
LeetCode94 二叉树的中序遍历
题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/description/

class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inOrder(result, root);
return result;
}
public void inOrder(List<Integer> result, TreeNode root){
if(root == null){
return;
}
inOrder(result, root.left);
result.add(root.val);
inOrder(result,root.right);
}
}
迭代遍历
文章讲解:https://programmercarl.com/二叉树的迭代遍历.html
视频讲解:
LeetCode 144 二叉树的前序遍历
题目链接:https://leetcode.cn/problems/binary-tree-preorder-traversal/
用栈来模拟递归过程,即可以使用 循环+栈 来替代递归法
前序遍历是根左右,但因为栈是先进后出,所以处理完根节点以后,先将非空右节点入栈,再将非空左节点入栈,这样出栈的时候就能保持根左右的顺序

class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preOrder(result, root);
return result;
}
public void preOrder(List<Integer> result, TreeNode root){
Stack<TreeNode> stack = new Stack<>();
if(root == null){
return;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
result.add(cur.val);
if(cur.right != null){
stack.push(cur.right);
}
if(cur.left != null){
stack.push(cur.left);
}
}
}
}
LeetCode145 二叉树的后序遍历
题目链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/description/
前序遍历是根左右,因为栈是先进后出,所以入栈的顺序是根右左,那么如果按根左右的顺序入栈,得到的遍历顺序是根右左,再将其反转就能得到左右根,即后序遍历顺序

class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
postOrder(result, root);
return result;
}
public void postOrder(List<Integer> result, TreeNode root){
Stack<TreeNode> stack = new Stack<>();
if(root == null){
return;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
result.add(cur.val);
if(cur.left != null){
stack.push(cur.left);
}
if(cur.right != null){
stack.push(cur.right);
}
}
Collections.reverse(result);
}
}
LeetCode94 二叉树的中序遍历
题目链接:https://leetcode.cn/problems/binary-tree-inorder-traversal/description/
中序遍历是左根右,先访问的是二叉树顶部节点,然后一层一层向下访问,直到到达树左面的最底部再开始处理节点,即处理顺序与访问顺序不一致
故在使用迭代法写中序遍历二叉树时,需要使用指针的遍历来帮助访问节点,栈则用来记录遍历的元素及处理节点元素

class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inOrder(result, root);
return result;
}
public void inOrder(List<Integer> result, TreeNode root){
if(root == null){
return;
}
TreeNode cur = root;
Stack<TreeNode> stack = new Stack<>();
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;
}
}
}
}
统一迭代
使用栈的话,无法同时解决访问节点(遍历节点)和处理节点(将元素放入结果集)不一致的情况,那我们就将访问的节点放入栈中,把要处理的节点也放入栈中,但是要额外打标记
如何打标记?使用空指针标记法,在要处理的节点放入栈后,紧接着放入一个空指针作为标记
以中序遍历为例,遍历到当前节点不为空,弹出该节点,再将非空右节点压入栈,再将中节点压入栈,中节点访问过但没处理,故再压入空节点做标记,之后再压入非空左节点
当遍历到当前节点为空节点时,先将空节点弹出,再弹出下一个元素,此元素即可加入结果集

class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack();
if(root != null){
stack.push(root);
}
while(!stack.isEmpty()){
TreeNode cur = stack.peek();
if(cur != null){
stack.pop(); // 将该节点弹出,避免重复操作,下面再将右中左节点添加到栈中(中序遍历-左中右,入栈顺序右中左)
if(cur.right != null){
stack.push(cur.right);
}
stack.push(cur);
stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记
if(cur.left != null){
stack.push(cur.left);
}
}else{ // 只有遇到空节点的时候,才将下一个节点放进结果集
stack.pop();
result.add(stack.pop().val);
}
}
return result;
}
}
层序遍历
文章讲解:https://programmercarl.com/0102.二叉树的层序遍历.html
视频讲解:https://www.bilibili.com/video/BV1GY4y1u7b2/?vd_source=b989f2b109eb3b17e8178154a7de7a51
LeetCode102 二叉树的层序遍历
题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/description/

class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
List<Integer> curLevel = new ArrayList<>();
int size = queue.size();
while(size > 0){
TreeNode curNode = queue.poll();
curLevel.add(curNode.val);
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
}
result.add(curLevel);
}
return result;
}
}
LeetCode107 二叉树的层序遍历Ⅱ
题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal-ii/description/

class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> records = new ArrayList<>();
if(root == null){
return records;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> curLevel = new ArrayList<>();
while(size > 0){
TreeNode curNode = queue.poll();
curLevel.add(curNode.val);
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
}
records.add(curLevel);
}
List<List<Integer>> result = new ArrayList<>();
for(int i = records.size()-1; i >= 0; i--){
result.add(records.get(i));
}
return result;
}
}
LeetCode199 二叉树的右视图
题目链接:https://leetcode.cn/problems/binary-tree-right-side-view/description/

class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
int record = 0;
while(size > 0){
TreeNode curNode = queue.poll();
if(size == 1){
record = curNode.val;
}
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
}
result.add(record);
}
return result;
}
}
LeetCode637 二叉树的层平均值
题目链接:https://leetcode.cn/problems/average-of-levels-in-binary-tree/description/

class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
int cnt = size;
double sum = 0;
while(size > 0){
TreeNode curNode = queue.poll();
sum += curNode.val;
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
}
double average = sum / cnt;
result.add(average);
}
return result;
}
}
LeetCode429 N叉树的层序遍历
题目链接:https://leetcode.cn/problems/n-ary-tree-level-order-traversal/description/

class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> records = new ArrayList<>();
while(size > 0){
Node curNode = queue.poll();
records.add(curNode.val);
for(int i = 0;i < curNode.children.size();i++){
Node child = curNode.children.get(i);
if(child != null){
queue.offer(child);
}
}
size--;
}
result.add(records);
}
return result;
}
}
LeetCode515 在每个树行中找最大值
题目链接:https://leetcode.cn/problems/find-largest-value-in-each-tree-row/description/

class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
int maxNum = Integer.MIN_VALUE;
while(size > 0){
TreeNode curNode = queue.poll();
if(maxNum < curNode.val){
maxNum = curNode.val;
}
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
}
result.add(maxNum);
}
return result;
}
}
LeetCode116 填充每个节点的下一个右侧节点指针
题目链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/

class Solution {
public Node connect(Node root) {
if(root == null){
return root;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
Node preNode = queue.poll();
if(preNode.left != null){
queue.offer(preNode.left);
}
if(preNode.right != null){
queue.offer(preNode.right);
}
size--;
while(size > 0){
Node curNode = queue.poll();
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
preNode.next = curNode;
preNode = curNode;
}
}
return root;
}
}
LeetCode117 填充每个节点的下一个右侧节点指针Ⅱ
题目链接:https://leetcode.cn/problems/populating-next-right-pointers-in-each-node-ii/

class Solution {
public Node connect(Node root) {
if(root == null){
return root;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
Node preNode = queue.poll();
if(preNode.left != null){
queue.offer(preNode.left);
}
if(preNode.right != null){
queue.offer(preNode.right);
}
size--;
while(size > 0){
Node curNode = queue.poll();
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
preNode.next = curNode;
preNode = curNode;
}
}
return root;
}
}
LeetCode104 二叉树的最大深度
题目链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/

class Solution {
public int maxDepth(TreeNode root) {
int depth = 0;
if(root == null){
return depth;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
if(size > 0){
depth++;
}
while(size > 0){
TreeNode curNode = queue.poll();
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
}
}
return depth;
}
}
LeetCode111 二叉树的最小深度
题目链接:https://leetcode.cn/problems/minimum-depth-of-binary-tree/description/

class Solution {
public int minDepth(TreeNode root) {
int depth = 0;
if(root == null){
return depth;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
int size = queue.size();
if(size > 0){
depth++;
}
while(size > 0){
TreeNode curNode = queue.poll();
if(curNode.left != null){
queue.offer(curNode.left);
}
if(curNode.right != null){
queue.offer(curNode.right);
}
size--;
if(curNode.left == null && curNode.right == null){
return depth;
}
}
}
return depth;
}
}

浙公网安备 33010602011771号