代码随想录算法训练营第十四天|LeetCode144.二叉树的前序遍历、LeetCode94.二叉树的中序遍历、LeetCode145.二叉树的后序遍历
2023年3月7日
第二十二天补
二叉树专题的第一天,这一天其实做了三题,分别是树的先序、中序、后序遍历
其中每道题我都跟着carl哥用三种方式解决:递归法、递归法、统一格式法
接下来三题每题我写三种解法
144. 二叉树的前序遍历
题目链接:144. 二叉树的前序遍历
递归法
思路:
- 写一个递归函数,参数传入递归的节点和记录元素的数组
- 注意在递归调用函数的顺序!
- 前序遍历:先插入当前元素的值,再遍历左孩子,再遍历右孩子
- 中序遍历:先遍历左孩子,再插入当前元素的值,再遍历右孩子
- 后序遍历:先遍历左孩子,再遍历右孩子,再插入当前元素的值
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> preorderTraversal(TreeNode *root)
{
vector<int> res;
travelTree(root,res);
return res;
}
void travelTree(TreeNode *node, vector<int> &v)
{
if (node == nullptr)
return;
v.push_back(node->val);
travelTree(node->left, v);
travelTree(node->right, v);
}
};
迭代法
思路: 手动用一个栈来实现递归的逻辑
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> preorderTraversal(TreeNode *root)
{
vector<int> res;
stack<TreeNode *> stk;
stk.push(root);
while (!stk.empty())
{
TreeNode *node = stk.top();
stk.pop();
if (node != nullptr)
{
res.push_back(node->val);
// 注意入栈顺序,后入栈的元素先放进数组,所以要先遍历右孩子,再遍历左孩子
stk.push(node->right);
stk.push(node->left);
}
else
continue;
}
return res;
}
};
统一格式法
思路:
- 对遍历过的中间节点,设置一个后缀进行标记
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> preorderTraversal(TreeNode *root)
{
vector<int> res;
stack<TreeNode *> stk;
if (root != nullptr)stk.push(root);
while (!stk.empty())
{
auto cur = stk.top();
if (cur != nullptr)
{
// 统一格式其实只需要改这里,由于存储入栈结构,存的顺序要反过来,前序遍历应是右左中
stk.pop();
if (cur->right != nullptr)stk.push(cur->right);
if (cur->left != nullptr)stk.push(cur->left);
stk.push(cur);
// 在中间节点后放放置空指针标记
stk.push(nullptr);
}
else
{
// 遇到是空指针了,就代表当前元素其实是遍历过的,需要插入数组
stk.pop();
cur = stk.top();
res.push_back(cur->val);
stk.pop();
}
}
return res;
}
};
总结:
- 加油哈
- 做题体验:
哈哈
(哈哈
>嘿嘿
>哎哎
>嘤嘤
) - 时间:
未计
一刷
94. 二叉树的中序遍历
题目链接:94. 二叉树的中序遍历
递归法
思路: 见上
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> inorderTraversal(TreeNode *root)
{
vector<int> res;
travelNode(root, res);
return res;
}
void travelNode(TreeNode *node, vector<int> &vct)
{
if (node == nullptr)
return;
travelNode(node->left, vct);
vct.push_back(node->val);
travelNode(node->right, vct);
}
};
迭代法
思路:
- 由于深度优先的遍历顺序,无法满足先遍历左孩子再便利父亲节点,又没有反转顺序的方式,所以中序遍历的迭代法要复杂一些
- 这里的代码是我自己想到的方式,不是太好,会破坏树的原本结构
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> inorderTraversal(TreeNode *root)
{
vector<int> res;
stack<TreeNode *> stk;
if (root != nullptr)
stk.push(root);
while (!stk.empty())
{
TreeNode *node = stk.top();
if (node->left != nullptr)
{
stk.push(node->left);
// 左指针制空,这样回退的时候知道这个节点遍历过
node->left = nullptr;
}
else
{
// 当前节点没有左孩子,可以输出当前节点
stk.pop();
res.push_back(node->val);
if (node->right != nullptr)
{
// 插入右孩子
stk.push(node->right);
// 右指针制空
node->right = nullptr;
}
}
}
return res;
}
};
统一格式法
思路:
- 同上
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> inorderTraversal(TreeNode *root)
{
vector<int> res;
stack<TreeNode *> stk;
if(root!=nullptr)stk.push(root);
while (!stk.empty())
{
auto cur = stk.top();
if(cur !=nullptr)
{
stk.pop();
if(cur->right!=nullptr)stk.push(cur->right);
stk.push(cur);
stk.push(nullptr);
if(cur->left!=nullptr)stk.push(cur->left);
}
else
{
stk.pop();
cur = stk.top();
res.push_back(cur->val);
stk.pop();
}
}
return res;
}
};
总结:
- 加油哈
- 做题体验:
哈哈
(哈哈
>嘿嘿
>哎哎
>嘤嘤
) - 时间:
未计
一刷
145. 二叉树的后序遍历
题目链接:145. 二叉树的后序遍历
递归法
思路: 见上
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> postorderTraversal(TreeNode *root)
{
vector<int> res;
travelTree(root, res);
return res;
}
void travelTree(TreeNode *node, vector<int> &res)
{
if (node == nullptr)
return;
travelTree(node->left, res);
travelTree(node->right, res);
res.push_back(node->val);
}
};
迭代法
思路:
- 因为深度遍历遇到节点的顺序,中间节点必然是先遇到,所以用迭代法会有局限性,无法在遍历完孩子节点之后遍历父亲节点
- 这道题要另想一个思路,前序遍历的顺序是中左右,后序遍历的顺序是左右中
- 那么如果改变孩子节点的遍历顺序,将前序遍历改成中右左,那么再反转数组,就可以得到后序遍历的序列化
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> postorderTraversal(TreeNode *root)
{
vector<int> res;
travelTree(root, res);
return res;
}
void travelTree(TreeNode *node, vector<int> &res)
{
if (node == nullptr)
return;
travelTree(node->left, res);
travelTree(node->right, res);
res.push_back(node->val);
}
};
统一格式法
思路:
- 同上
时间复杂度:O(n)
,空间复杂度O(n)
代码:
class Solution
{
public:
vector<int> postorderTraversal(TreeNode *root)
{
vector<int> res;
stack<TreeNode *> stk;
if(root!=nullptr)stk.push(root);
while (!stk.empty())
{
auto cur = stk.top();
if(cur !=nullptr)
{
// 后序遍历:左右中
// 入栈顺序:中右左
stk.pop();
stk.push(cur);
stk.push(nullptr);
if(cur->right!=nullptr)stk.push(cur->right);
if(cur->left!=nullptr)stk.push(cur->left);
}
else
{
stk.pop();
cur = stk.top();
res.push_back(cur->val);
stk.pop();
}
}
return res;
}
};
总结:
- 加油哈
- 做题体验:
哈哈
(哈哈
>嘿嘿
>哎哎
>嘤嘤
) - 时间:
未计
一刷