剑指offer树相关问题,目录:
4.重建二叉树
17.树的子结构
18.二叉树的镜像
22.从上往下打印二叉树
23.二叉搜索树的后序遍历序列
24.二叉树中和胃某一值的路径
26.二叉搜索树与双向链表
37.二叉树的深度
38.平衡二叉树
57.二叉树的下一个结点
58.对称的二叉树
59.按之字顺序打印二叉树
60.把二叉树打印成多行
61.二叉搜索树的第k个结点
62.序列化二叉树
代码
4.重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/*
根据中序遍历和前序遍历确定二叉树:
1.前序序列的第一个结点为根结点
2.根据根结点在中序序列中的位置分割出左右两个子序列
3.对左子树和右子树分别递归使用同样的方向进行分解
时间复杂度O(n)
空间复杂度O(n)
*/
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
int len = vin.size();
if (len == 0) return NULL;
vector<int> left_pre,right_pre,left_in,right_in;
TreeNode *head = new TreeNode(pre[0]); //先序序列的第一个结点为根结点
//找到中序序列的根结点位置,存放与gen中
int gen =0;
for(int i=0;i<len;i++){
if(vin[i] == pre[0]){
gen = i;
break;
}
}
//中序遍历中,根结点左边的结点位于二叉树的左边,根结点右边的结点位于二叉树的右边
//分别存入序列中
for(int i=0;i<gen;i++){
left_in.push_back(vin[i]);
left_pre.push_back(pre[i+1]);
}
for(int i=gen+1;i<len;i++){
right_in.push_back(vin[i]);
right_pre.push_back(pre[i]);
}
//递归
head->left=reConstructBinaryTree(left_pre,left_in);
head->right=reConstructBinaryTree(right_pre,right_in);
return head;
}
};
17.树的子结构
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
/*
在树A中找到和树B结构一样的子树。
第一步:在树A中找到和B跟结点一样的结点R -->树的遍历,使用递归来实现
第二步:判断树A中以R为结点的子树是否包含和树B一样的结构 -->采用递归,如果根结点相同,则递归地判断他们各自的左右结点的值是否相同,递归的出口是我们到达了树A或者树B的叶子结点。
*/
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
bool re=false;
if(pRoot1 != NULL && pRoot2 != NULL){
if(pRoot1->val ==pRoot2->val)
re=HasTree2(pRoot1,pRoot2);
if(!re)
re=HasSubtree(pRoot1->left,pRoot2);
if(!re)
re=HasSubtree(pRoot1->right,pRoot2);
}
return re;
}
bool HasTree2(TreeNode* pRoot1,TreeNode* pRoot2){
if(pRoot2 == NULL)
return true;
if(pRoot1==NULL)
return false;
if(pRoot1->val != pRoot2->val)
return false;
return HasTree2(pRoot1->left,pRoot2->left) && HasTree2(pRoot1->right,pRoot2->right);
}
};
18.二叉树的镜像
操作给定的二叉树,将其变换为源二叉树的镜像。
输入描述:
二叉树的镜像定义:源二叉树
8
/
6 10
/ \ /
5 7 9 11
镜像二叉树
8
/
10 6
/ \ /
11 9 7 5
//先序遍历二叉树,交换非叶子结点的左右子树。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
void Mirror(TreeNode *pRoot) {
if((pRoot == NULL) || (pRoot->left ==NULL && pRoot->right ==NULL))
return;
TreeNode *ptemp = pRoot->left;
pRoot->left = pRoot->right;
pRoot->right = ptemp;
if(pRoot->left)
Mirror(pRoot->left);
if(pRoot->right)
Mirror(pRoot->right);
}
};
22.从上往下打印二叉树
题目描述
从上往下打印出二叉树的每个节点,同层节点从左至右打印。
/*
使用队列层次遍历二叉树
第一步:将根结点加入队列
第二步:当队列不为空时循环,队头结点出队,如果有左右孩子结点就加入队列。
*/
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
vector<int> res;
queue<TreeNode*> q;
TreeNode* t;
if(root ==NULL) return res;
q.push(root);
while(!q.empty()){
t=q.front();
q.pop();
res.push_back(t->val);
if(t->left !=NULL) q.push(t->left);
if(t->right != NULL) q.push(t->right);
}
return res;
}
};
23.二叉搜索树的后序遍历序列
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
/*
二叉搜索树的后序遍历中,最后一个数字是树的根结点。左子树的结点都比根结点小,右子树的结点都比根结点大。
*/
class Solution {
public:
bool VerifySquenceOfBST(vector sequence) {
int length_=sequence.size();
if (length_ == 0) return false;
int i=0;
while(–length_){
while(sequence[i++]<sequence[length_]);
while(sequence[i++]>sequence[length_]);
if (i<length_) return false;
i=0;
}
return true;
}
};
24.二叉树中和胃某一值的路径
输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)
/*
使用前序遍历访问到某一个结点时,将该结点添加到路径上,并累加该结点的值。
如果当前结点符合要求,则打印出来。
如果不符合,且不为叶子结点,则继续访问它的子结点。访问结束后,递归函数自动回到它的父结点。
*/
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int>> res;
vector<int> tmp;
void dfs(TreeNode* root ,int k){
tmp.push_back(root->val);
if((k-root->val) == 0 && !root->left && !root->right){
res.push_back(tmp);
}
else{
if(root->left) dfs(root->left,k-root->val);
if(root->right) dfs(root->right,k-root->val);
}
tmp.pop_back();
}
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
if(root) dfs(root,expectNumber);
return res;
}
};
26.二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
/*
二叉树中,每个结点都有两个指向子结点的指针。双向链表中,每个结点也有个指向前一结点和后一结点的两个指针。结点结构相似,理论上可以实现互相转换。
中序遍历排序二叉树可以按照从小到大的顺序遍历每一个结点。
使用递归的方法进行转换:
将左右子树转换成排序双链表之后,再和根结点链接起来。
转换方法:
(1)将当前结点的左指针指向双链表的尾部
(2)链表尾部的右指针指向当前结点
(3)更新尾指针
*/
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
TreeNode* pLastOfList=NULL;
//定义当前结点,双链表尾结点
ConvertNode(pRootOfTree,&pLastOfList);
TreeNode* pHeadOfList=pLastOfList;
while(pHeadOfList!=NULL && pHeadOfList->left!=NULL ){
pHeadOfList=pHeadOfList->left;
}
return pHeadOfList;
}
void ConvertNode(TreeNode* pNode,TreeNode** pLastOfList){
if(pNode==NULL) return ;
TreeNode* pCurrent = pNode;
if(pCurrent->left!=NULL){
ConvertNode(pCurrent->left,pLastOfList);
}
//1 当前节点的左指针指向双链表结尾
pCurrent->left = *pLastOfList;
//2 结尾的右指针指向当前节点
if((*pLastOfList)!=NULL){
(*pLastOfList)->right = pCurrent;
}
//3:更新双链表的尾指针
(*pLastOfList) = pCurrent;
if(pCurrent->right !=NULL){
ConvertNode(pCurrent->right,pLastOfList);
}
}
};
37.二叉树的深度
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
//树的深度->树的最长路径
//树的深度=max(左子树深度,右子树深度)+1
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
int TreeDepth(TreeNode* pRoot)
{
if(pRoot ==NULL) return 0;
int nLeft =TreeDepth(pRoot->left);
int nRight=TreeDepth(pRoot->right);
return (nLeft>nRight)?(nLeft+1):(nRight+1);
}
};
38.平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
/*
递归方法:
遍历树点每个结点的时候,记录它的左右子树深度,如果每个结点的左右子树的深度相差不超过1,则是平衡二叉树。
每个结点只遍历一次:
使用后序遍历的方法遍历二叉树,并对比左右子树的深度。
*/
class Solution {
public:
bool IsBalanced_Solution(TreeNode* pRoot) {
int depth=0;
return IsBalanced(pRoot,&depth);
}
bool IsBalanced(TreeNode* pRoot,int* depth){
if(pRoot==NULL){
*depth=0;
return true;
}
int left,right;
if(IsBalanced(pRoot->right,&right)&&IsBalanced(pRoot->left,&left)){
int d = abs(left-right);
if(d<=1){
*depth=1+(left>right?left:right);
return true;
}
}
return false;
}
};
57.二叉树的下一个结点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
/*
中序遍历的顺序为:左根右
1.有右子树,下一结点为:右子树的最左结点。
2.没有右子树:
(1)是父结点的左孩子,下一结点:父结点
(2)父结点的右孩子,一直向上找,直到结点是父结点的左孩子。一直没有,则是尾结点。
*/
/*
struct TreeLinkNode {
int val;
struct TreeLinkNode *left;
struct TreeLinkNode *right;
struct TreeLinkNode *next;
TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
}
};
*/
class Solution {
public:
TreeLinkNode* GetNext(TreeLinkNode* pNode)
{
if(pNode==NULL) return NULL;
if(pNode->right!=NULL){
pNode=pNode->right;
while(pNode->left!=NULL)
pNode=pNode->left;
return pNode;
}
while(pNode->next!=NULL){
TreeLinkNode* pRoot=pNode->next;
if(pRoot->left==pNode)
return pRoot;
pNode=pNode->next;
}
return NULL;
}
};
58.对称的二叉树
请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
//递归判断左右子树是否相等。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
return IsSym(pRoot,pRoot);
}
bool IsSym(TreeNode* root1,TreeNode* root2){
if(root1==NULL && root2==NULL) return true;
else if(root1==NULL || root2==NULL) return false;
else if(root1->val != root2->val) return false;
return IsSym(root1->left,root2->right) && IsSym(root1->right,root2->left);
}
};
59.按之字顺序打印二叉树
请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
int layer=1;
//s1存储奇数层结点
Stack<TreeNode> s1= new Stack<TreeNode>();
s1.push(pRoot);
//s2存储偶数层结点
Stack<TreeNode> s2=new Stack<TreeNode>();
ArrayList<ArraList<Integer>> list = new ArrayList<ArrayList<int>>();
while (!s1.empty() || !s2.empty()) {
if (layer%2 != 0) {
ArrayList<Integer> temp = new ArrayList<Integer>();
while (!s1.empty()) {
TreeNode node = s1.pop();
if(node != null) {
temp.add(node.val);
System.out.print(node.val + " ");
s2.push(node.left);
s2.push(node.right);
}
}
if (!temp.isEmpty()) {
list.add(temp);
layer++;
System.out.println();
}
} else {
ArrayList<Integer> temp = new ArrayList<Integer>();
while (!s2.empty()) {
TreeNode node = s2.pop();
if(node != null) {
temp.add(node.val);
System.out.print(node.val + " ");
s1.push(node.right);
s1.push(node.left);
}
}
if (!temp.isEmpty()) {
list.add(temp);
layer++;
System.out.println();
}
}
}
return list;
}
};
60.把二叉树打印成多行
从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
//层次遍历
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
vector<vector<int> > Print(TreeNode* pRoot) {
vector<vector<int> > vec;
if(pRoot == NULL) return vec;
queue<TreeNode*> q;
q.push(pRoot);
while(!q.empty())
{
int lo = 0, hi = q.size();
vector<int> c;
while(lo++ < hi)
{
TreeNode *t = q.front();
q.pop();
c.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
vec.push_back(c);
}
return vec;
}
};
61.序列化二叉树
请实现两个函数,分别用来序列化和反序列化二叉树
二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 ! 表示一个结点值的结束(value!)。
二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
62.二叉搜索树的第k个结点
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
/*
二叉搜索树中,每个结点的左子树均小于该结点,右子树均大于该结点
所以按照中序序列打印出来的顺序就是排序好的顺序
按照中序遍历顺序找到第k个结点
*/
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
int count=0;
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(pRoot == NULL)
return NULL;
TreeNode* node = KthNode(pRoot->left,k);
if(node != NULL)
return node;
count++;
if(count == k)
return pRoot;
node = KthNode(pRoot->right,k);
if(node !=NULL)
return node;
}
};