Problem: 145. 二叉树的后序遍历
方法一:递归
思路
二叉树的遍历方式主要有前序遍历,中序遍历,后序遍历以及层序遍历。其中前序、中序、后序是深度优先算法,层序是广度优先算法。
前序遍历按照 左子树 → 右子树 → 根节点 左子树 \rightarrow 右子树 \rightarrow 根节点 左子树→右子树→根节点的顺序进行遍历,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。
我们将原问题拆分成了更小规模的问题:递归遍历左子树,递归遍历右子树,输出根。
递归边界条件:节点为空
Code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
function<void(TreeNode*)> dfs = [&](TreeNode* node){
if(node == nullptr) return;
dfs(node->left);
dfs(node->right);
res.push_back(node->val);
};
dfs(root);
return res;
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n),其中 n n n是二叉树的节点数 -
空间复杂度:
O ( n ) O(n) O(n),当二叉树为链状时
方法二:迭代
思路
在递归过程中,我们隐式地维护了一个栈,在迭代过程中,我们可以将栈显式地模拟出来。
先将数按照 根 → 左节点 根 \rightarrow 左节点 根→左节点的顺序放入栈中。依次出栈,若是左节点直接输出。若为根节点则需要先将右节点放入栈中。此时右节点作为子树的根,需要继续执行上述迭代操作。
当右子树遍历完毕后,输出根。
Code
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
TreeNode* pre; //判断右子树是否访问完毕
while(root || !stk.empty()){
while(root){
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
if(root->right == nullptr || pre == root->right){ // 根节点在右子树为空或者右子树遍历完后加入结果
res.push_back(root->val);
pre = root;
root = nullptr;
}else{
stk.push(root); //右子树还未遍历,先遍历右子树,将根放入栈中
root = root->right;
}
}
return res;
}
};
复杂度
-
时间复杂度:
O ( n ) O(n) O(n),其中 n n n是二叉树的节点数 -
空间复杂度:
O ( n ) O(n) O(n),当二叉树为链状时