二叉树相关算法

二叉树类算法

一、二叉树的路径和:二叉树的每个节点为0-9的一个数字,根到叶子的一条路径拼成一个数,求所有路径形成的数字和
struct TreeNode
{
    TreeNode* left;
    TreeNode* right;
    int value;
};
 
int dfs(TreeNode* root, int sum)
{
    if (root == nullptr)
    {
        return 0;
    }
    if (root->left == nullptr && root->right == nullptr)
    {
        return sum * 10 + root->value;
    }
    return dfs(root->left, sum * 10 + root->value)
         + dfs(root->right, sum * 10 + root->value);
}
 
int SumOfPath(TreeNode* root)
{
    return dfs(root, 0);
}


二、二叉树的路径:输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。
 
/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    //这类问题可以用带记忆的DFS来解决。分享一个这类问题的典型解法。
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int>> ret;
        vector<int> trace;
        if(root)
            dfs(root,expectNumber,ret,trace);
        return ret;
    }
    void dfs(TreeNode* root,int s,vector<vector<int>> &ret,vector<int> &trace) {
        trace.push_back(root->val);
        if(!root->left&&!root->right) {
            if(s==root->val)
                ret.push_back(trace);
        }
        if(root->left)
            dfs(root->left,s-root->val,ret,trace);
        if(root->right)
            dfs(root->right,s-root->val,ret,trace);
        trace.pop_back();
    }
};

二叉树的直径: 给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

示例 :
给定二叉树

      1
     / \
    2   3
   / \     
  4   5    

返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。

class Solution {
    int ans;
    int depth(TreeNode* root){
        if (root == NULL) return 0;
        int L = depth(root->left);
        int R = depth(root->right);
        ans = max(ans, L + R + 1);
        return max(L, R) + 1;
    }
public:
    int diameterOfBinaryTree(TreeNode* root) {
        ans = 1;
        depth(root);
        return ans - 1;
    }
};

三、二叉树的深度:输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot == nullptr)
            return 0;
        int left = TreeDepth(pRoot->left);
        int right = TreeDepth(pRoot->right);
        return max(left, right) + 1;
    }
};

四、判断平衡二叉树:输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
class Solution {
public:
    bool IsBalanced_Solution(TreeNode* pRoot) {
        if (!pRoot) return true;
        int left = depth(pRoot->left);
        int right = depth(pRoot->right);
        return abs(left - right) <= 1 && IsBalanced_Solution(pRoot->left) && IsBalanced_Solution(pRoot->right);
    }
    int depth(TreeNode* pRoot) {
        if (!pRoot) return 0;
        return max(depth(pRoot->left), depth(pRoot->right)) + 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,diff;
         if(IsBalanced(pRoot->left,left) && IsBalanced(pRoot->right,right)){
             diff=left-right;
             if(diff<=1 && diff>=-1){
                 depth=left>right?left+1:right+1;
                 return true;
             }
         }
         return false;
    }
};

五、二叉树的镜像:请完成一个函数,输入一个二叉树,该函数输出它的镜像。
/*
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) return;
        TreeNode *temp = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = temp;
        Mirror(pRoot->left);
        Mirror(pRoot->right);
    }
};

六、对称二叉树:请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。
class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        return issymmetrical(pRoot,pRoot);
    }
    bool issymmetrical(TreeNode* pRoot1,TreeNode* pRoot2){
        if(pRoot1==NULL && pRoot2==NULL)
            return true;
        if(pRoot1==NULL || pRoot2==NULL)
            return false;
        if(pRoot1->val!=pRoot2->val)
            return false;
        return issymmetrical(pRoot1->right,pRoot2->left) && issymmetrical(pRoot1->left,pRoot2->right);
    }

};

七、二叉搜索树的第k小节点:给定一棵二叉搜索树,请找出其中第k大的节点。二叉搜索树的中序遍历是从小到大的顺序遍历(自左往右是第K小,自右往左是第k大)。

借用额外空间:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int kthLargest(TreeNode* root, int k) {
        vector<int> vec;
        inorder(root, vec);
        return vec[vec.size() - k];
    }
    void inorder(TreeNode* node, vector<int>& vec) {
    	//中序遍历,将节点按从小到大顺序保存在vec中
        if (node->left)
            inorder(node->left, vec);
        vec.push_back(node->val);
        if (node->right)
            inorder(node->right, vec);
    }
};

不用额外空间:


class Solution {
public:
  TreeNode* KthNodeCore(TreeNode* pRoot, int& k)
  {
        TreeNode* target = NULL;
        if(pRoot->left != NULL)//先在左子树中找
            target = KthNodeCore(pRoot->left, k);
        //如果左子树中没找到,即没有执行(if(k==1)这个语句),所以target==NULL,继续在根结点中找
       if(target == NULL)
        {
            if(k == 1)
                target = pRoot;
          //根结点没有,但已经找了一个结点了,故k减一,直到K等于1时,当前结点就是要求的结点。。
            k--;
        }
       //如果还是没找到,则继续在右子树中找。
        if(target == NULL&&pRoot->right != NULL)
            target = KthNodeCore(pRoot->right, k);
        return target;
    }
    
    TreeNode* KthNode(TreeNode* pRoot, int k)
    {
         if(pRoot == NULL || k == 0)
       		 return NULL;   
        return KthNodeCore(pRoot, k);
    }  
};

八、二叉树的最近公共祖先:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

8.1: 如果二叉树是二叉搜索树:二叉搜索树是排序过的,位于左子树的结点都比父结点小,而位于右子树的结点都比父结点大,我们只需要从树的根结点开始和两个轮入的结点进行比较 如果当前结点的值比两个结点的值都大,那么最低的共同父结点一定是在当前结点的左子树中,于是下一步遍历当前结点的左子结点 如果当前结点的值比两个结点的值都小,那么最低共同父结点一定在当前结点的右子树中,于是下一步遍历当前结点的右子结点。这样在树中从上到下找到的第一个处于两个节点值之间的节点就是最近公共祖先。

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {     
        if (!root) {
            return root;
        }   
        if (root->val > max(p->val, q->val)) {
            
            return lowestCommonAncestor(root->left, p, q);
        }
        else if (root->val < min(p->val, q->val)) {     
            return lowestCommonAncestor(root->right, p, q);
        }
        else {       
            return root;
        }
    }
};

8.2: 非二叉搜索树,但节点含有一个指向父节点的指针。如果树中的每个结点(除根结点之外)都有一个指向父结点的指针,这个问题可以转换成求两个链表的笫一个公共结点。假设树结点中指向父结点的指针是 pParent, 那么从树的每一个叶结点开始都有一个由指针 pParent 串起来的链表,这些链表的尾指针都是树的根节点。输入两个节点,那么这两个节点位于两个链表上,它们的最低公共祖先就是两个链表的第一个公共节点。

int Hight(BinaryNode* root, BinaryNode* node)  
{  
    int len = 0;  
    for (; node != NULL; node = node->_parent)  
        len++;  
  
    return len;  
} 

BinaryNode* GetLastCommonAncestor(BinaryNode* root, BinaryNode* node1, BinaryNode* node2)  
{   
    if (root == NULL || node1 == NULL || node2==NULL)  
        return NULL;  
    int len1 = Hight(root,node1);  
    int len2 = Hight(root,node2);       
  
    for (; len1 > len2; len1--)  
        node1 = node1->_parent;  
    for (; len2 > len1; len2--)  
        node2 = node2->_parent;  
  
    while (node1 && node2 && node1 != node2)  
    {  
        node1 = node1->_parent;  
        node2 = node2->_parent;  
    }  
      
    if (node1 == node2)  
        return node1;  
    else  
        return NULL;  
}

8.3:非二叉搜索树,且不含有父节点指针。通过先序遍历,获取根节点到目标节点的路径,再通过获取的路径,求的公共节点。

class Solution {
public:
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		if (root == NULL || p == NULL || q == NULL) return NULL;
		list<TreeNode*> path1, path2;
		GetNodePath(root, p, path1);
		GetNodePath(root, q, path2);
		return GetLastCommonNode(path1, path2);
	}
	//获取从根节点到目标节点的路径
	bool GetNodePath(TreeNode* root, TreeNode* node, list<TreeNode*>& path)
	{
        //先把root节点加入到list中
		path.push_back(root);
		//找到目标节点
		if (root == node)  return true;
		//标志符found
		bool found = false;
		if (!found && root->left != NULL) found = GetNodePath(root->left, node, path);
		if (!found && root->right != NULL) found = GetNodePath(root->right, node, path);
		//如果没有找到,则返回头节点时,删除当前节点
		if (!found)
		{
			path.pop_back();
		}
		return found;
	}
	//获取共同节点
	TreeNode* GetLastCommonNode(list<TreeNode*> path1, list<TreeNode*> path2)
	{
		TreeNode* pLast = nullptr;
		list<TreeNode*>::iterator it1 = path1.begin();
		list<TreeNode*>::iterator it2 = path2.begin();
		while (it1!=path1.end()&&it2!=path2.end())
		{
			if (*it1 == *it2) pLast = *it1;
			it1++;
			it2++;
		}
		return pLast;
	}
};

九、在一棵满二叉排序树深度为k,节点数为2^k-1;节点值为1至(2^k - 1),给出k和任意三个节点的值,输出包含该三个节点的最小子树的根节点。

样例输入:4 10 15 13; 样例输出:12

首先,我们来理解一下满二叉排序树,如下就是一个4层的满二叉排序树:

 *          8
 *        /   \
 *       4     12
 *      / \   /   \
 *     2  6   10   14
 *    /\  /\  / \ /  \
 *   1 3 5 7 9 11 13 15

根据上图可以看出,满二叉排序树的中序遍历是从1到2^k - 1的递增序列(k为层数)。所以,只要给出层数我们就能够确定这个二叉排序树。同时,观察可知,二叉排序树从上到下的根节点刚好是所有元素进行二分查找的中间节点。

根据上面的规律要解决三个节点的最小子树的根节点这个问题可以得到如下几点:无须建立二叉树,从1-2^k - 1的递增数组即就是一个满二叉排序树。

  1. 当输入的三个元素在二分节点两侧时,当前的二分节点就是要查找的最小子树的根节点(根据这个规则,我们也无需判断三个元素,只需判断最大元素和最小元素的位置即可)
  2. 当最小节点的值大于二分节点的值,则继续在二分的右半部分进行查找
  3. 当最大节点的值小于二分节点的值,则继续在二分的左半部分进行查找。
//1.按位右移运算符(m>>n)  将数据m除以2^n(2的n次方)
//2.按位左移运算符(m<<n)  将数据m乘以2^n(2的n次方)
// int right=(1<<k)-1; //把1左移k位,===》2^k  
//arr为3个节点值从小到大排列的数组。
int FindMin(int* arr,int left,int right)  
{  
    int mid=((right-left)>>1)+left;  
    if(arr[0]<=mid&&arr[2]>=mid)  
        return mid;  
    else if(arr[0]>mid)  
        return FindMin(arr,mid+1,right);  
    else if(arr[2]<mid)  
        return FindMin(arr,left,mid-1);  
} 

问题二:如何创建一个k层的(1~2^k - 1)满二叉排序树。

TreeNode* solution(int start,int end){
	if (start>end)
		return nullptr;
	int mid=(start+end)/2
	TreeNode* head= new TreeNode;
	head->value=mid;
	head->left =solution(start,mid-1);
	head->right=solution(mid+1,end);
	return head;
}

十、二叉排序树转换成有序双向链表

题目描述: 将二叉排序树转换成一个排序的双向链表,要求:不能创建任何新的节点,只能通过调整指针的指向来实现.
分析: 二叉排序树的一个很重要的特性就是:二叉树中序遍历的结果是一个递增的序列。由这个特性可以知道该题需要通过中序遍历的思想来解决。按照中序遍历的递归思路,先遍历左子树,然后处理根节点,最后遍历右子树。关键的步骤在于处理根节点。我们通过中序递归遍历过程中的一个状态来解析转换的过程,当中序遍历root指向10时,要满足转换成双向有序链表的请求,结点10左指针必须指向它中序遍历的前一个结点8,而前一个结点8的右指针必须指向结点10。设置一个初始的last节点,假设它是双链表的最后一个节点。root的left指向last,last的right指向root,最后用root代替原来的last,root就成了双向链表的最后一个节点

//结点的结构
struct BSTNode{
    int data;
    BSTNode *left;
    BSTNode *right;
};

//主函数
BSTNode* Convert2DoubleLinkList(BSTNode *root)
{
    if(root == NULL)    
        return NULL;

    BSTNode *last = NULL;

    //二叉排序树转换成排序双向链表
    Convert(root, &last);

    //取得双向链表的头指针
    while(root->left != NULL)
        root = root->left;

    return root;
}

//二叉排序树转换成双向链表
void Convert(BSTNode *root, BSTNode** last)
{
    if(root == NULL)
        return;

    //遍历左子树
    Convert(root->left, last);

    //处理根节点
    root->left = *last;
    if((*last) != NULL)
        (*last)->right = root;
    *last = root;

    //遍历右子树
    Convert(root->right, last);
}

十一、已排序的双向链表转变成平衡二叉树

#include "stdafx.h"
#include "vector"
#include "list"
 
typedef struct node
{
    int val;
    struct node *pre;
    struct node *rear;
}NODE;
 
 
 
NODE *getMiddleNode(NODE *pStart, NODE *pEnd)
{
    NODE *pFast;
    NODE *pSlow;
 
    if (!pStart)
        return NULL;
 
    if (pStart->pre == pEnd)
        return NULL;
 
    if (pStart == pEnd)
    {
        pStart->pre  = NULL;
        pStart->rear = NULL;
        return pStart;
    }
 
    pFast = pStart;
    pSlow = pStart;
 
    while ((pFast != pEnd) && (pFast ->rear != pEnd))
    {
        pFast = pFast->rear->rear;
        pSlow = pSlow->rear;
    }
 
    return pSlow;
}
NODE* convertLinkToTree(NODE *pHead, NODE *pRear)
{
    NODE *pMiddle = getMiddleNode(pHead, pRear);
 
    if (pMiddle)
    {
        pMiddle->pre  = convertLinkToTree(pHead, pMiddle->pre);
        pMiddle->rear = convertLinkToTree(pMiddle->rear, pRear);
    }
 
    return pMiddle;
}

十二、子树的判断

题目描述: 输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)。B是A的子结构, 即 A中有出现和B相同的结构和节点值。
分析: 判断B是不是A的子树,需要在A中找B。先遍历A树,遇到节点值和B树根节点相同时的节点时,判断它下面的节点是不是和B相同,这里就可以用一个递归函数来实现。递归函数的作用是:输入两个节点,判断以这两个节点为根节点的树是否完全相同。若在A中找到了这样一个节点,和B树的值完全相同,则B就是A的子树。

//主函数,判断pRoot2是不是pRoot1的子树
bool HasSubTree(TreeNode* pRoot1, TreeNode* pRoot2)
{
    //若两个树有任意一个为空树,直接返回false
    if (!pRoot1 || !pRoot2) return false;
    //如果pRoot1的根节点和pRoot2的根节点值相同,就需要判断这两棵树剩下的部分是否相同,所以调用递归函数IsSametree
    bool result =false;
    if (pRoot1->val == pRoot2->val)
        result= IsSametree(pRoot1, pRoot1);
    //如果pRoot1的根节点和pRoot2的根节点值不同,那么需要往下遍历A树,找它的左右节点,有任意一个节点满足条件时,B就是A的子树
    if (!result) 
        result= HasSubTree(pRoot1->left, pRoot2);
    if (!result) 
        result= HasSubTree(pRoot1->right, pRoot2);
	return result;
}
//调用函数,判断以这两个节点为根节点的树是否完全相同
bool IsSametree(TreeNode* pRoot1, TreeNode* pRoot2)
{
    //如果两个节点同时为空,则是相同的树
    if (!pRoot1 && !pRoot2) return true;
    //如果两个节点不同时为空,则肯定不是相同的树
    if (!pRoot1 || !pRoot2) return false;
    //两个节点都有值,但节点值不同,那肯定不是相同的树
    if (pRoot1->val != pRoot2->val)
        return false;
    //如果值相同,则判断他们的左右节点是否也相同(必须都相同才行)
    else
        return IsSametree(pRoot1->left,pRoot2->left) && IsSametree(pRoot1->right,pRoot2->right);
}

十三、二叉树的搜索
题目:输入一个二叉搜索树的根节点,实现一个调度器,调用调度器的next()方法,将返回二叉树中下一个最小的数;调用迭代器的hasNext()方法,将返回是否存在下一个数。next() 和 hasNext() 操作的时间复杂度是 O(1),并使用 O(h) 内存,其中 h 是树的高度。你可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 中至少存在一个下一个最小的数。

class BSTIterator {
private:
    vector<TreeNode*> S;
public:
    BSTIterator(TreeNode* root){
        while(root){
            S.push_back(root);
            root = root->left;
        }
    }
    int next() {
        TreeNode* t = S.back();
        S.pop_back();
        int val = t->val;
        t = t->right;
        while(t){
            S.push_back(t);
            t = t->left;
        }
        return val;
    }
    bool hasNext() {
        return !S.empty();
    }
};

十四、二叉树的遍历

递归:


typedef struct TreeNode
{
    int data;
    TreeNode * left;
    TreeNode * right;
}TreeNode;
 
void pre_order(TreeNode * Node)//前序遍历递归算法
{
    if(Node == NULL)
        return;
    printf("%d ", Node->data);//显示节点数据,可以更改为其他操作。在前面
    pre_order(Node->left);
    pre_order(Node->right);
}
void middle_order(TreeNode *Node)//中序遍历递归算法
{
    if(Node == NULL)
        return;
    middle_order(Node->left);
    printf("%d ", Node->data);//在中间
    middle_order(Node->right);
}
void post_order(TreeNode *Node)//后序遍历递归算法
{
    if(Node == NULL)
        return; 
    post_order(Node->left);
    post_order(Node->right);
    printf("%d ", Node->data);//在最后
}


非递归:

//前序遍历
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if(!root) return {};
        stack<TreeNode*> s;
        vector<int> res;
        s.push(root);
        while(!s.empty()) {
            TreeNode* temp=s.top();
            s.pop();
            res.push_back(temp->val);
            if(temp->right) s.push(temp->right);
            if(temp->left) s.push(temp->left); 
        }
        return res;
    }
};

//中序遍历
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> s;
        vector<int> res;
        TreeNode* temp=root;
        while(temp||!s.empty()) {
            if(temp) {
                s.push(temp);
                temp=temp->left;
            }
            else {
                temp=s.top();
                res.push_back(temp->val);
                s.pop();
                temp=temp->right;
            }
        }
        return res;
    }
};
//后序遍历
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if(!root) return {};
        stack<TreeNode*> stack1,stack2;
        vector<int> res;
        stack1.push(root);
        while(!stack1.empty()) {
            TreeNode* temp=stack1.top();
            stack1.pop();
            stack2.push(temp);
            if(temp->left) stack1.push(temp->left);
            if(temp->right) stack1.push(temp->right);
        }
        while(!stack2.empty()) {
            res.push_back(stack2.top()->val);
            stack2.pop();
        }
        return res;
    }
};
//层序遍历
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        queue<TreeNode*> q;
        if(root) q.push(root);
        while(!q.empty()) {
            int n=q.size();
            vector<int> level;
            for(int i=0;i<n;i++) {
                TreeNode* temp=q.front();
                q.pop();
                level.push_back(temp->val);
                if(temp->left) q.push(temp->left);
                if(temp->right) q.push(temp->right);
            }
            res.push_back(level);
        }
        return res;
    }    
 };

十五、重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示的二叉树并输出它的头结点。

//构建二叉树的函数,前序遍历和中序遍历的起始位置与长度
BinaryTreeNode *Construct(int *preorder, int *inorder, int length)
{
	if(preorder == NULL || inorder == NULL || length <= 0) {
		printf("invalid input!\n");
		return 0;
	}
 
	return ConstructCore(preorder, preorder + length -1, inorder, inorder + length - 1);
}
 
BinaryTreeNode *ConstructCore(int *startPreorder,int *endPreorder,int *startInorder,int *endInorder)
{
    //前序遍历的第一个元素,即为根节点
	int rootValue = startPreorder[0];
    //构建根节点
	BinaryTreeNode * root = (BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
	root->m_nValue = rootValue;
	root->m_pLeft = root->m_pRight = NULL;
 
    //顺序遍历到最后一个元素
	if (startPreorder == endPreorder)
	{
        //该节点满足是根节点的条件如括号中所示
		if (startInorder == endInorder && *startPreorder == *startInorder) {
            return root;
        } else {
            printf("invalid input!\n");
        }	
	}
 
    //根据前序遍历中的根节点的值,在中序遍历中找到根节点
	int* rootInorder = startInorder;
	while(rootInorder <= endInorder && *rootInorder != rootValue) {
        ++rootInorder;
    }	
 
	if(rootInorder == endInorder && *rootInorder != rootValue) {
        printf("invalid input!\n");
    }
 
    //在中序数组中找到它的左子树的长度
	int leftLength = rootInorder - startInorder;
    //根据中序遍历中左子树的长度在前序遍历中找到左子树的位置
	int* leftPreorderEnd = startPreorder + leftLength;
 
	if(leftLength > 0){
        //构建左子树,输入为前序遍历子串的起始地址,中序遍历的起始地址
		root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
	}
 
	if(leftLength < (endPreorder - startPreorder))
    {
        //构建右子树,输入为前序遍历子串的起始地址,中序遍历的起始地址
		root->m_pRight = ConstructCore(leftPreorderEnd + 1,endPreorder, rootInorder + 1, endInorder);
    }
 
	return root;
}

十六、二叉树的后序搜索序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

后序遍历 的序列中,最后一个数字是树的根节点, 数组中前面的数字可以分为两部分:第一部分是左子树节点 的值,都比根节点的值小; 第二部分 是右子树 节点的值,都比 根 节点 的值大,后面用递归分别判断前后两部分 是否 符合以上原则

BST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),如果去掉最后一个元素的序列为T, 那么T满足:T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列。完美的递归定义 ) 。


class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(!sequence.size())
            return false;
        return judge(sequence,0,sequence.size()-1);
 
    }
    
    bool judge(vector<int> &a,int l,int r)//l为左边界 r 为右边界
    {
        if(l>=r) return true;
  
        /*比如1 4 3 5这个二叉搜索树的后序遍历,没有右子树,
        所以r一直对应的是4这个索引,当return judge(a, l, i - 1) && (judge(a, i, r - 1))中的第二个递归
        i=r,r-1<r,所以应该是返回true
        l==r对应的是叶子结点,l>r对应的是空树,这两种情况都是true
        */
        
        int i=r;
        while(i>l&&a[i-1]>a[r])//i 一直移动 移动到左子树边界  判定条件即右子树所有节点都需要大于根节点
            --i;
        for(int j=i-1;j>=l;--j)//j为i-1即相对于根节点的左子树,遍历左子树 如果左子树中有任何一个节点大于根节点 return false
        {
            if(a[j]>a[r])
            {
                return false;
            }
        }
        return judge(a,l,i-1)&&judge(a,i,r-1);    
    }     
};

十七、已知两个二叉树,当合并两个树时,我们需要满足当这个位置的节点只有一个树有时,直接复制此节点,如果这个节点位置两个树都有的时候,我们需要把两个树同一位置的值加起来,成为一个新的节点。

在这里插入图片描述

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。


class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if(t1==NULL){
            return t2;
        }
        if(t2==NULL){
            return t1;
        }
        t1->val=t1->val+t2->val;
        t1->left=mergeTrees(t1->left, t2->left);
        t1->right=mergeTrees(t1->right, t2->right);
        return t1;
    }
};

十八、二叉树的右视图

给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

思路:二叉树的层次遍历,每层添加进去后计数后添加左子节点或右子节点,循环到计数值之后,即为最右节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> rightSideView(TreeNode* root) {
        queue<TreeNode*> q;
        vector<int> v;
        if(NULL==root) return v;
        q.push(root);
       
        int m=1;
        while(!q.empty())
        {
            int n=0;
            for(int i=0;i<m;i++)
            {
                TreeNode* t=q.front();
                //i==m-1是每一层的最后边的结点,i==0是每一层最前面的结点
                //所以求左视图的话,只需要把i==m-1换成i==0即可
                if(i==m-1) v.push_back(t->val);
                q.pop();//一定要弹出
                if(t->left) 
                {
               //利用队列存储二叉树结点
                    q.push(t->left);
                    //利用整数n记录每个层的结点个数
                    n++;
                }
                if(t->right) 
                {
                    q.push(t->right);
                    n++;
                }
            }
            m=n;//维持m
        }
    return v;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值