2023-02-23
Leetcode
00

目录

前言
1. 二叉树的前序遍历
1.1 题目描述
1.2 解法一:递归
1.3 解法二:迭代
2. 二叉树的后序遍历
2.1 题目描述
2.2 解法一:递归
2.3 解法二:迭代

前言

拒绝摆烂ヾ(◍°∇°◍)ノ゙

从今天开始(2023/02/12),定一个小目标,先刷个 300Leetcode 题目(之前刷的不计入)。

当然作为一个小前端,我选择的语言是 TS,而且刷的题目的难度会偏中等一些,大概按照 简单3 中等6 困难1 这样的题型分布吧。嗯,目前是这么打算的。

本题 Github 地址:因为比较喜欢 vscode 的界面,而且方便调试,所以 AC 完就顺便提到 github 了,也算做一个记录吧。

本篇的题目是这个系列的第 NO.4NO.5 道,分别是 Leetcode 上第 144 道题 二叉树的前序遍历, 和第 145 道题 二叉树的后序遍历,难度都为 简单

我们开始吧,Here We Go~

1. 二叉树的前序遍历

1.1 题目描述

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:

输入: root = [1,null,2,3] 输出: [1,2,3]

示例 2:

输入: root = [] 输出: []

示例 3:

输入: root = [1] 输出: [1]

示例 4:

输入: root = [1,2] 输出: [1,2]

示例 5:

输入: root = [1,null,2] 输出: [1,2]

提示:

  • 树中节点数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

1.2 解法一:递归

树的先序遍历的过程:

  1. 优先访问根节点
  2. 之后访问左子树
  3. 最后访问右子树

这种递归地方法是一种很容易理解的方法,只要在访问左右子树之前将当前节点的值 push 到最终的 ret 数组中即可。

ts
function preorderTraversal(root: TreeNode | null): number[] { let ret: number[] = []; function traversal(root: TreeNode | null) { if(!root) return root.val !== null && ret.push(root.val); traversal(root.left); traversal(root.right); } traversal(root); return ret; }

复杂度分析:

  • 时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
  • 空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)

1.3 解法二:迭代

我们也可以用迭代的方式实现方法一的递归函数,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同。

ts
function preorderTraversal(root: TreeNode | null): number[] { let ret: number[] = []; if (!root) return []; let stack: TreeNode[] = [root]; while (stack.length) { const node = stack.pop()!; if (node.val !== null) ret.push(node.val); node.right && stack.push(node.right); node.left && stack.push(node.left); } return ret; }

2. 二叉树的后序遍历

2.1 题目描述

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

示例 1:

输入: root = [1,null,2,3] 输出: [3,2,1]

示例 2:

输入: root = [] 输出: []

示例 3:

输入: root = [1] 输出: [1]

提示:

  • 树中节点的数目在范围 [0, 100] 内
  • -100 <= Node.val <= 100

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

2.2 解法一:递归

树的后序遍历的过程:

  1. 优先访问左子树
  2. 之后访问右子树
  3. 最后访问根节点

后续遍历递归的方法就是将遍历 root.val 的顺序放在了 遍历左节点遍历右节点 之后

ts
function postorderTraversal(root: TreeNode | null): number[] { let ret: number[] = []; function traversal(root: TreeNode | null) { if(!root) return traversal(root.left); traversal(root.right); root.val !== null && ret.push(root.val); } traversal(root); return ret; }

复杂度分析:

  • 时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
  • 空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)

2.3 解法二:迭代

同样,我们也可以用迭代的方式实现方法一的递归函数,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其余的实现与细节都相同。

ts
function postorderTraversal(root: TreeNode | null): number[] { let ret: number[] = []; let stack: TreeNode[] = []; let current: TreeNode | null = root; let lastVisitedNode: TreeNode | null = null; while (stack.length || current !== null) { while (current !== null) { stack.push(current); current = current.left; } current = stack[stack.length - 1]; if (current.right === null || current.right === lastVisitedNode) { ret.push(current.val); lastVisitedNode = current; stack.pop(); current = null; } else { current = current.right; } } return ret; }

复杂度分析:

  • 时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
  • 空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:叶继伟

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!