590. N 叉树的后序遍历题解
题目来源:590. N 叉树的后序遍历
2022.03.12 每日一题
LeetCode 题解持续更新中Github仓库地址 CSDN博客地址
今天的题目比较简单,同时也可以参考 前天的每日一题 N 叉树的前序遍历一起来做一下,都是有关于树的遍历
树的遍历分为前序遍历、中序遍历、后序遍历以及层序遍历四种,(具体详解最晚周一放链接,最近有点忙。orz)
递归法
第一个方法就是老生常谈的,最简单的那个递归法,易于理解,还能简单
class Solution {
public:
vector<int> postorder(Node *root) {
vector<int> res;
dfs(root, res);
return res;
}
void dfs(Node *root, vector<int> &res) {
if (root == nullptr)
return;
for (auto &node: root->children) {
dfs(node, res);
}
res.push_back(root->val);
}
};
class Solution {
public List<Integer> postorder(Node root) {
List<Integer> list = new ArrayList<>();
dfs(root, list);
return list;
}
void dfs(Node root, List<Integer> list) {
if (root == null) return;
for (Node node : root.children) {
dfs(node, list);
}
list.add(root.val);
}
}
-
时间复杂度 O ( n ) O(n) O(n)
-
空间复杂度 O ( 1 ) O(1) O(1)
数据结构 栈
递归的思路可以由数据结构中的栈进行模拟,进入递归相当于向栈中放入元素,跳出递归相当于从栈中取出元素的过程
后序遍历就是首先得到子节点的 val 然后逐步向上,由二叉树举例就是 左右中 的顺序
由此我们可以先将根节点放入栈中,然后倒序放入其子节点序列,以保证可以按顺序取出相应元素
同时创建一个 HashSet 进行统计,判断该节点其子节点是否被全部遍历一遍
class Solution {
public:
vector<int> postorder(Node *root) {
vector<int> res;
if (root == nullptr)
return res;
// 创建一个队列 来执行迭代
stack<Node *> st;
// 创建一个 HashSet 来统计 每个节点的子节点是否完全被遍历过一次
unordered_set<Node *> cnt;
st.push(root);
// 不停的循环,直到 栈中的元素为空
while (!st.empty()) {
// 取栈中的顶层元素进行判断
Node *temp = st.top();
// 如果 其没有 children 序列
// 或者 其子序列已经被遍历过一次
// 就进行统计
// 并将其移除
if (temp->children.size() == 0 || cnt.count(temp)) {
res.push_back(temp->val);
st.pop();
continue;
}
// 如果其子节点序列不为空
// 或者仍未访问过,则将其子节点序列压入栈中
// 等待下一次迭代
// 由于我们统计是从左到右顺序统计,因此我们在压入栈中的时候要倒序压入,以便后续迭代
for (auto it = temp->children.rbegin(); it != temp->children.rend(); it++) {
st.push(*it);
}
// 此节点其子节点已经被遍历过了,因此放入 HashSet 中进行标记
cnt.insert(temp);
}
return res;
}
};
class Solution {
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList();
if (root == null) return res;
// 创建一个队列 来执行迭代
Deque<Node> st = new ArrayDeque<>();
// 创建一个 HashSet 来统计 每个节点的子节点是否完全被遍历过一次
Set<Node> cnt = new HashSet();
st.push(root);
// 不停的循环,直到 栈中的元素为空
while (!st.isEmpty()) {
// 取栈中的顶层元素进行判断
Node temp = st.peek();
// 如果 其没有 children 序列
// 或者 其子序列已经被遍历过一次
// 就进行统计
// 并将其移除
if (temp.children.size() == 0 || cnt.contains(temp)) {
res.add(temp.val);
st.pop();
continue;
}
// 如果其子节点序列不为空
// 或者仍未访问过,则将其子节点序列压入栈中
// 等待下一次迭代
// 由于我们统计是从左到右顺序统计,因此我们在压入栈中的时候要倒序压入,以便后续迭代
for (int i = temp.children.size() - 1; i >= 0; i--)
st.push(temp.children.get(i));
// 此节点其子节点已经被遍历过了,因此放入 HashSet 中进行标记
cnt.add(temp);
}
return res;
}
}
- 时间复杂度 O ( n ) O(n) O(n)
- 空间复杂度 O ( n ) O(n) O(n)