二叉树小练习
1.根据二叉树创建字符串
需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。空节点则用一对空括号 “()” 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
class Solution {
public:
string tree2str(TreeNode* root){
string str;
_tree2str(root,str);
return str;
}
void _tree2str(TreeNode* root,string& str) {
if(root==nullptr)
{
return;
}
str += to_string(root->val);
//左不为空 或者 左为空右不为空
if(root->left || root->right)
{
str += "(";
_tree2str(root->left,str);
str += ")";
}
//右不为空
if(root->right)
{
str += "(";
_tree2str(root->right,str);
str += ")";
}
return;
}
};
2.二叉树的层序遍历
层序遍历Ⅰ 逐层地,从左到右访问所有节点
层序遍历Ⅱ 按从叶子节点所在层到根节点所在的层,逐层从左向右遍历
层序遍历Ⅱ就是在层序遍历Ⅰ的基础上进行一个逆序,所以就只写一个层序遍历Ⅱ
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*> q;
vector<vector<int>> res;
if(root==NULL){
return res;
}
q.push(root);
while(!q.empty())
{
vector<int> temp;
for(int i=q.size();i>0;i--)
{
TreeNode* node = q.front();
q.pop();
temp.push_back(node->val);
if(node->left!=NULL){
q.push(node->left);
}
if(node->right!=NULL){
q.push(node->right);
}
}
res.push_back(temp);
}
reverse(res.begin(),res.end());
return res;
}
};
3.二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
公共祖先的定义:对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
class Solution {
public:
bool FindPath(TreeNode* root,stack<TreeNode*>& path, TreeNode* x)
{
if(root==nullptr)
{
return false;
}
path.push(root);
if(root==x)
{
return true;
}
if(FindPath(root->left,path,x))
{
return true;
}
if(FindPath(root->right,path,x))
{
return true;
}
//左右都没找到
path.pop();
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
stack<TreeNode*> p_path;
stack<TreeNode*> q_path;
FindPath(root,p_path,p);
FindPath(root,q_path,q);
stack<TreeNode*>* longPath = &p_path;
stack<TreeNode*>* shortPath = &q_path;
if(p_path.size() < q_path.size())
{
swap(longPath,shortPath);
}
//长的先走
while(longPath->size()>shortPath->size())
{
longPath->pop();
}
//同时走
while(longPath->top()!=shortPath->top())
{
longPath->pop();
shortPath->pop();
}
return longPath->top();
}
};
4.二叉搜索树和双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
class Solution {
public:
Node *pre, *head;
void dfs(Node* cur) {
if(cur == nullptr)
{
return;
}
dfs(cur->left);
if(pre != nullptr)
{
pre->right = cur;
}
else
{
head = cur;
}
cur->left = pre;
pre = cur;
dfs(cur->right);
}
Node* treeToDoublyList(Node* root) {
if(root == nullptr)
{
return nullptr;
}
dfs(root);
head->left = pre;
pre->right = head;
return head;
}
};
5.根据一棵树的前序遍历与中序遍历构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
class Solution {
public:
TreeNode* _buildTree(vector<int>& preorder,int& pi,vector<int>& inorder,int inBegin,int inEnd)
{
if(inBegin>inEnd)
{
return nullptr;
}
TreeNode* root = new TreeNode(preorder[pi]);
++pi;
//查找root在中序遍历中的位置,划分左右子树
int rooti=inBegin;
while(rooti<=inEnd)
{
if(root->val==inorder[rooti])
break;
else
++rooti;
}
root->left = _buildTree(preorder,pi,inorder,inBegin,rooti-1);
root->right = _buildTree(preorder,pi,inorder,rooti+1,inEnd);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
{
int i=0;
return _buildTree(preorder,i,inorder,0,inorder.size()-1);
}
};
6.根据一棵树的中序遍历与后序遍历构造二叉树
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
//5.6题目和5.5类似,就在5.5的基础上稍微改造了一下
class Solution {
public:
TreeNode* _buildTree(vector<int>& postorder,int& pi,vector<int>& inorder,int inBegin,int inEnd)
{
if(inBegin>inEnd)
{
return nullptr;
}
TreeNode* root = new TreeNode(postorder[pi]);
--pi;
//查找root在中序遍历中的位置,划分左右子树
int rooti=inBegin;
while(rooti<=inEnd)
{
if(root->val==inorder[rooti])
break;
else
++rooti;
}
root->right = _buildTree(postorder,pi,inorder,rooti+1,inEnd);
root->left = _buildTree(postorder,pi,inorder,inBegin,rooti-1);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder)
{
int i=postorder.size()-1;
return _buildTree(postorder,i,inorder,0,inorder.size()-1);
}
};
7.二叉树的前序遍历(非递归)
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> ret;
TreeNode* cur = root;
while(!st.empty()||cur)//cur指向哪个节点就表示开始前序访问这棵树
{
//访问左路节点,左路节点入栈
while(cur)
{
ret.push_back(cur->val);
st.push(cur);
cur = cur->left;
}
//依次取左路节点的右子树出来访问
TreeNode* top = st.top();
st.pop();
//子问题去访问这些右子树
cur = top->right;
}
return ret;
}
};
8.二叉树的中序遍历(非递归)
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> ret;
TreeNode* cur = root;
while(!st.empty()||cur)//cur指向哪个节点就表示开始前序访问这棵树
{
//左路节点入栈
while(cur)
{
st.push(cur);
cur = cur->left;
}
//依次取左路节点的右子树出来
TreeNode* top = st.top();
ret.push_back(top->val);
st.pop();
//子问题去访问这些右子树
cur = top->right;
}
return ret;
}
};
9.二叉树的后序遍历(非递归)
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> ret;
TreeNode* cur = root;
TreeNode* prev = nullptr;
while(!st.empty()||cur)//cur指向哪个节点就表示开始前序访问这棵树
{
//左路节点入栈
while(cur)
{
st.push(cur);
cur = cur->left;
}
//取到一个栈顶元素,他的左路节点已经访问完了
//如果他的右为空或者右子树已经访问完了,那么我们就可以访问栈顶元素
TreeNode* top = st.top();
if(top->right==nullptr || top->right==prev)
{
st.pop();
ret.push_back(top->val);
prev = top;
}
else
{
cur = top->right;
}
}
return ret;
}
};