目录
[1. 二叉树创建字符串](#1. 二叉树创建字符串)
[2. 二叉树的分层遍历1](#2. 二叉树的分层遍历1)
[3. 二叉树的分层遍历2](#3. 二叉树的分层遍历2)
[4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先](#4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先)
[5. 二叉树搜索树转换成排序双向链表](#5. 二叉树搜索树转换成排序双向链表)
1. 二叉树创建字符串
题目
给你二叉树的根节点 root
,请你采用前序遍历的方式,将二叉树转化为一个由括号和整数组成的字符串,返回构造出的字符串。
空节点使用一对空括号对 "()"
表示,转化后需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
分析
如下图所示
这道题要求打印出表示二叉树关系的字符串,这样应该很简单,但是又要求省略掉不必要的空括号,这就需要判断什么情况下的括号是不必要的括号,很显然,如果一个结点的左子树为空,但是右子树不为空,这时候代表左子树的那个括号就一定不能省略,在其他情况下则都是可以省略的,根据这些我们可以写出如下代码
代码
cpp
class Solution {
public:
string tree2str(TreeNode* root) {
string ret;
if(root==nullptr)
return "";
ret+=to_string(root->val);
//当左子树不为空
if(root->left)
{
ret+="(";
ret+=tree2str(root->left);
ret+=")";
}
//当左子树为空,右子树不为空
if(root->right&&root->left==nullptr)
{
ret+="()";
}
//当右子树不为空
if(root->right)
{
ret+="(";
ret+=tree2str(root->right);
ret+=")";
}
return ret;
}
};
2. 二叉树的分层遍历1
题目
给你二叉树的根节点 root
,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
分析
这道题就是对二叉树进行层序遍历,即根据深度来依次遍历,遍历完上一层的所有结点才能访问下一层的。
这时候我们需要一个变量levelsize来帮助我们记录当前深度下一共有多少个结点,来帮助我们能遍历完当前层的所有结点,并且在遍历上一层结点的同时把下一层结点的个数统计出来,依次循环下去达到我们的目的。
代码
cpp
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> vv;
if (root == nullptr) {
return vv;
}
// 先记录第一层的结点个数(一定为1)
int levelSize = 1;
queue<TreeNode*> q;
// 将第一层的所有结点插入队列(只有一个根节点)
q.push(root);
while (!q.empty()) {
// 记录当前层的所有结点的值
vector<int> v;
// 遍历完当前层的所有结点
while (levelSize--) {
// 获得当前结点并将该节点弹出
TreeNode* cur = q.front();
q.pop();
v.push_back(cur->val);
// 将下一层的结点插入到队列
if (cur->left) {
q.push(cur->left);
}
if (cur->right) {
q.push(cur->right);
}
}
// 刷新levelSize为下一层的结点个数
levelSize = q.size();
// 将当前层的所有结点的值填入二维数组
vv.push_back(v);
}
return vv;
}
};
3. 二叉树的分层遍历2
题目
给你二叉树的根节点 root
,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
分析
与上一题输出相反,我们可以对上一题得到的二维数组vv进行倒转,即使用reverse函数进行逆置。
在上一题的return vv;前加一个
cpp
reverse(vv.begin(),vv.end());
代码
cpp
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> vv;
if (root == nullptr) {
return vv;
}
// 先记录第一层的结点个数(一定为1)
int levelSize = 1;
queue<TreeNode*> q;
// 将第一层的所有结点插入队列(只有一个根节点)
q.push(root);
while (!q.empty()) {
// 记录当前层的所有结点的值
vector<int> v;
// 遍历完当前层的所有结点
while (levelSize--) {
// 获得当前结点并将该节点弹出
TreeNode* cur = q.front();
q.pop();
v.push_back(cur->val);
// 将下一层的结点插入到队列
if (cur->left) {
q.push(cur->left);
}
if (cur->right) {
q.push(cur->right);
}
}
// 刷新levelSize为下一层的结点个数
levelSize = q.size();
// 将当前层的所有结点的值填入二维数组
vv.push_back(v);
}
reverse(vv.begin(),vv.end());
return vv;
}
};
4. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
题目
分析
这里我们可以找出p和q路径上的所有祖先结点插入栈中,然后pop出栈对p和q路径上的结点依次比较,从而找到最近的公共祖先结点。
代码
cpp
class Solution {
public:
bool createPath(TreeNode* root, TreeNode* t, stack<TreeNode*>& st)
{
if (root == nullptr)
return false;
st.push(root);
if (root == t)
return true;
if (createPath(root->left, t, st))
return true;
if (createPath(root->right, t, st))
return true;
st.pop();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> p_path;
stack<TreeNode*> q_path;
//插入p和q路径上的所有结点到栈中
createPath(root, p, p_path);
createPath(root, q, q_path);
//使得两个条路径的结点个数一样
while (p_path.size() != q_path.size())
{
if (p_path.size() > q_path.size())
p_path.pop();
else
q_path.pop();
}
//寻找最近的公共结点
while (p_path.top()!=q_path.top())
{
p_path.pop();
q_path.pop();
}
return p_path.top();
}
};
5. 二叉树搜索树转换成排序双向链表
题目
分析
如果说可以创建新的结点,那这题比较简单,但是题目要求不能创建新节点,只能调整当前结点的指向来完成双向链表的创建。
代码
cpp
class Solution {
public:
void order(TreeNode* root, TreeNode*& preNode)
{
if (root == nullptr)
return;
if (root->left)
order(root->left, preNode);
root->left = preNode;
if (preNode)
preNode->right = root;
preNode = root;
if (root->right)
order(root->right, preNode);
}
TreeNode* Convert(TreeNode* pRootOfTree) {
if (pRootOfTree == nullptr)
return nullptr;
TreeNode* preNode = nullptr;
order(pRootOfTree, preNode);
TreeNode* head = pRootOfTree;
while (head->left)
{
head = head->left;
}
return head;
}
};