文章目录
1.三种遍历方式
2.二叉树的镜像
请完成一个函数,输入一个二叉树,该函数输出它的镜像。
题目链接
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if(root==NULL)
return root;
swap(root->left,root->right);
mirrorTree(root->left);
mirrorTree(root->right);
return root;
}
};
3.对称的二叉树
请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
题目链接
class Solution {
public:
bool Judge(TreeNode *left,TreeNode *right)
{
if(left==NULL&&right==NULL)
return true;
if(left==NULL||right==NULL)//不同时为空
return false;
return
(left->val==right->val)&&//判断当前的镜像值是否相等
Judge(left->left,right->right)&&
Judge(left->right,right->left);
}
bool isSymmetric(TreeNode* root) {
if(!root)
return true;
return Judge(root->left,root->right);
}
};
4.二叉树的深度
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL)
return 0;
int left_depth=maxDepth(root->left)+1;
int right_depth=maxDepth(root->right)+1;
return fmax(left_depth,right_depth);
}
};
5.平衡二叉树
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
题目链接
6.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
题目链接
class Solution {
public:
TreeNode* _buildTree(vector<int>& preorder, vector<int>& inorder,int &prev_sub,int in_start,int in_end)
{
if(in_start>in_end)//空树
return NULL;
TreeNode *root=new TreeNode(preorder[prev_sub]);
//在中序中查找,根节点
int index=in_start;
while(index<in_end)
{
if(preorder[prev_sub]==inorder[index])
break;
else
index++;
}
if(in_start<=index-1)//左区间里面还有值
root->left=_buildTree(preorder,inorder,++prev_sub,in_start,index-1);
else
root->left=NULL;
if(index+1<=in_end)//右区间里面还有值
root->right=_buildTree(preorder,inorder,++prev_sub,index+1,in_end);
else
root->right=NULL;
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int prev_sub=0;
return _buildTree(preorder,inorder,prev_sub,0,inorder.size()-1);
}
};
7.树的子结构
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。
题目链接
class Solution {
public:
bool _isSubStructure(TreeNode* A, TreeNode* B)//判断两棵树是否相等
{
if(B==NULL)
return true;
if(A==NULL&&B!=NULL)
return false;
return
(A->val==B->val)&&
_isSubStructure(A->left,B->left)&&
_isSubStructure(A->right,B->right);
}
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(A==NULL||B==NULL)//遍历完了,还没有找到对应的结构
return false;
if(_isSubStructure(A,B))
return true;
return isSubStructure(A->left,B)||isSubStructure(A->right,B);//遍历A
}
};
8.从上至下打印二叉树I
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
题目链接
class Solution {
public:
vector<int> ret;
queue<TreeNode*>q;
vector<int> levelOrder(TreeNode* root) {
if(root==NULL)
return ret;
q.push(root);
while(!q.empty())
{
TreeNode *root=q.front();
q.pop();
ret.push_back(root->val);
if(root->left!=NULL)
q.push(root->left);
if(root->right!=NULL)
q.push(root->right);
}
return ret;
}
};
9.从上至下打印二叉树II
从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
题目链接
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ret;
queue<TreeNode*> q1;
queue<TreeNode*> q2;
if(root==NULL)
return ret;
q1.push(root);
while(!q1.empty()||!q2.empty())
{
vector<int> temp1;
while(!q1.empty())
{
TreeNode *root=q1.front();
q1.pop();
temp1.push_back(root->val);
if(root->left!=NULL)
q2.push(root->left);
if(root->right!=NULL)
q2.push(root->right);
}
ret.push_back(temp1);
vector<int> temp2;
while(!q2.empty())
{
TreeNode *root=q2.front();
q2.pop();
temp2.push_back(root->val);
if(root->left!=NULL)
q1.push(root->left);
if(root->right!=NULL)
q1.push(root->right);
}
if(temp2.size()!=0)
ret.push_back(temp2);
}
return ret;
}
};
10.从上至下打印二叉树III
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
题目链接
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ret;
stack<TreeNode*> st1;
stack<TreeNode*> st2;
if(root==NULL)
return ret;
st1.push(root);
while(!st1.empty()||!st2.empty())
{
vector<int> temp1;
while(!st1.empty())
{
TreeNode *root=st1.top();
st1.pop();
temp1.push_back(root->val);
//从左至右放入st2之中
if(root->left)
st2.push(root->left);
if(root->right)
st2.push(root->right);
}
ret.push_back(temp1);
vector<int> temp2;
while(!st2.empty())
{
TreeNode *root=st2.top();
st2.pop();
temp2.push_back(root->val);
//从右至左放入st1之中
if(root->right)
st1.push(root->right);
if(root->left)
st1.push(root->left);
}
if(temp2.size()!=0)
ret.push_back(temp2);
}
return ret;
}
};
11.二叉树中和为某一值的路径
输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
题目链接
class Solution {
public:
void _pathSum(TreeNode* root, int target,vector<vector<int>> &ret,vector<int> &temp,int sum)
{
if(root==NULL)
return ;
temp.push_back(root->val);
sum+=root->val;
if(sum==target&&root->left==NULL&&root->right==NULL)
ret.push_back(temp);
_pathSum(root->left, target,ret,temp,sum);
_pathSum(root->right, target,ret,temp,sum);
temp.pop_back();//回溯
}
vector<vector<int>> pathSum(TreeNode* root, int target) {
vector<vector<int>> ret;
vector<int> temp;
int sum=0;
_pathSum(root, target,ret,temp,sum);
return ret;
}
};
12. 二叉搜索树的第k大节点
给定一棵二叉搜索树,请找出其中第k大的节点。
题目链接
class Solution {
public:
void _kthLargest(TreeNode* root, int &k,int &ret)
{
if(root==NULL||k==0)//为空或者K=0都不需要再进行下去
return ;
_kthLargest(root->right,k,ret);
k--;//当前访问到了一个节点,统计数减1
if(k==0)
{
ret=root->val;
return ;
}
_kthLargest(root->left,k,ret);
}
int kthLargest(TreeNode* root, int k) {
int ret=0;
_kthLargest(root,k,ret);
return ret;
}
};
13.二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
题目链接
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root->val>p->val&&root->val>q->val||root->val<p->val&&root->val<q->val)
{
if(root->val>p->val)//比两个节点的值都大,则往左边走
root=root->left;
else if(root->val<p->val)//比两个节点的值都小,则往右边走
root=root->right;
}
//此时,刚刚好,root等于其中一个节点,或者节点位于root的一左一右
return root;
}
};
14. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL)
return 0;
if(root==p||root==q)
return root;
TreeNode *left_node=lowestCommonAncestor(root->left,p,q);
TreeNode *right_node=lowestCommonAncestor(root->right,p,q);
if(left_node==NULL)//左边为空则都在右侧
return right_node;
if(right_node==NULL)//右侧为空则在左侧
return left_node;
return root;//都不为空,则当前节点就是根节点
}
};
15.不同的二叉搜索树
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
class Solution {
public:
int numTrees(int n) {
vector<int> ret(n+1,0);
ret[0]=1;//0棵树时,为空时一种情况
ret[1]=1;//一颗树时一种情况
if(n<2)
return ret[n];
ret[2]=2;//两棵树时两种情况
// ret[i]=ret[i-1]*ret[0]+ret[i-2]*ret[1] +....+ ret[0]*ret[i-1]
for(int i=3;i<=n;i++)
{
for(int j=0;j<i;j++)
{
ret[i]+= ret[j]*ret[i-j-1];
}
}
return ret[n];
}
};
16.二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
题目链接
class Solution {
public:
int _maxPathSum(TreeNode* root,int &count)
{
if(root==nullptr)
return 0;
int left=_maxPathSum(root->left,count);
int right=_maxPathSum(root->right,count);
int val=root->val;
//找出当前子树路径最大值
int temp1=val+left+right;
int temp2=val+left;
int temp3=val+right;
int temp4=fmax(temp1,fmax(temp2,temp3));
//记录下来
count=fmax(temp4,count);
//判断对上层是否有贡献
if(temp2<0&&temp3<0)
{
if(val<0)
return 0;
return val;
}
return fmax(temp2,temp3);
}
int maxPathSum(TreeNode* root) {
int count=root->val;
_maxPathSum(root,count);
return count;
}
};
17.从中序与后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树。
题目链接
class Solution {
public:
TreeNode* _buildTree(vector<int>&inorder,vector<int>&postorder,int &pos,int begin,int end)
{
int index=begin;
while(index<end)
{
if(inorder[index]!=postorder[pos])//在中序之中寻找
index++;
else
break;
}
//构造根节点
TreeNode* root=new TreeNode(postorder[pos]);
//划分区间,构建左右子树
if(index+1<=end)
root->right=_buildTree(inorder,postorder,--pos,index+1,end);//构造右子树
if(begin<=index-1)
root->left=_buildTree(inorder,postorder,--pos,begin,index-1);//构造左子树
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
int pos=postorder.size()-1;
if(pos<0)//空树
return nullptr;
return _buildTree(inorder,postorder,pos,0,inorder.size()-1);
}
};
18.从前序与中序遍历序列构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树。
题目链接
class Solution {
public:
TreeNode* _buildTree(vector<int>&preorder,vector<int>&inorder,int &prev,int begin,int end)
{
if(begin>end)
return nullptr;
int index=begin;
while(index<end)
{
if(inorder[index]!=preorder[prev])
index++;
else
break;
}
//构造根节点
TreeNode* root=new TreeNode(preorder[prev]);
//构造左右子树
if(index>begin)//构造左区间
root->left=_buildTree(preorder,inorder,++prev,begin,index-1);
if(index<end)
root->right=_buildTree(preorder,inorder,++prev,index+1,end);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int prev=0;
return _buildTree(preorder,inorder,prev,0,inorder.size()-1);
}
};
19.二叉树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
题目链接
class Solution {
public:
void _Convert(TreeNode* root,TreeNode*& prev)
{
if(root==nullptr)
return ;
_Convert(root->left,prev);
root->left=prev;
if(prev)
prev->right=root;
prev=root;
_Convert(root->right,prev);
}
TreeNode* Convert(TreeNode* pRootOfTree) {
TreeNode *prev=nullptr;
if(pRootOfTree==nullptr)
return nullptr;
TreeNode* head=pRootOfTree;
while(head->left)//不断往左走,找到头节点
{
head=head->left;
}
_Convert(pRootOfTree,prev);
return head;
}
};
20. 二叉树的层序遍历||
给定一个二叉树,返回其节点值自底向上的层序遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
题目链接
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> ret;
if(root==nullptr)
return ret;
queue<TreeNode*>q;
q.push(root);
int count=1;
while(!q.empty())
{
vector<int> temp;
while(count--)
{
TreeNode *node=q.front();
temp.push_back(node->val);
q.pop();
//下一层入队列
if(node->left)
q.push(node->left);
if(node->right)
q.push(node->right);
}
count=q.size();
ret.push_back(temp);
}
reverse(ret.begin(),ret.end());
return ret;
}
};
21.根据二叉树创建字符串
class Solution {
public:
void _tree2str(TreeNode *root,string &str)
{
if(root==nullptr)
return;
str+=to_string(root->val);//加入值
if(root->left==nullptr&&root->right==nullptr)//左右孩子都为空
return ;
str+='(';//左孩子括号始终要加上
_tree2str(root->left,str);
str+=')';
if(root->right==nullptr)
return ;
str+='(';
_tree2str(root->right,str);
str+=')';
}
string tree2str(TreeNode* root) {
string str;
if(root==nullptr)
return str;
_tree2str(root,str);
return str;
}
};
22.非递归前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int>ret;
TreeNode *Left=nullptr;
if(root)
{
st.push(root);
ret.push_back(root->val);
Left=root->left;
}
while(!st.empty()||Left)
{
while(Left)//左子树不为空则一直走下去
{
ret.push_back(Left->val);
st.push(Left);//将左子树入栈
Left=Left->left;
}
//此时左子树全部走完,开始走右子树
Left=st.top()->right;
st.pop();
}
return ret;
}
};
23.非递归中序遍历
中序遍历的方式是:左、根、右 -> 因此可以先将全部的根节点入栈 ->再取出来打印,获取其右子树
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int>ret;
stack<TreeNode*>st;
TreeNode* Left=nullptr;
if(root)
{
st.push(root);
Left=root->left;
}
while(!st.empty()||Left)
{
while(Left)
{
st.push(Left);//入栈
Left=Left->left;//往左走
}
//此时左节点全在栈中
Left=st.top();//从栈中拿值
st.pop();
ret.push_back(Left->val);//存值
Left=Left->right;//往右走
}
return ret;
}
};
24.非递归后续遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ret;
stack<TreeNode*>st;
TreeNode* prev=nullptr;//记录上一个被访问过的节点
TreeNode* Left=nullptr;
if(root)
{
st.push(root);
Left=root->left;
}
while(!st.empty()||Left)
{
while(Left)//将左子树全部入栈
{
st.push(Left);
Left=Left->left;
}
TreeNode* node=st.top();//从栈中获取节点
if(node->right==nullptr||node->right==prev)//右子树为空,或者已经访问过了
{
ret.push_back(node->val);
prev=node;//记录下来
st.pop();//出栈
}
else
Left=node->right;//否则获取该节点的右子树
}
return ret;
}
};