二叉树相关算法

2023-11-03

二叉树类算法

一、二叉树的路径和:二叉树的每个节点为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;
    }
};

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二叉树相关算法 的相关文章

随机推荐

  • 第一章、银行会计的基本原理和基本核算方法

    各位技术大牛 这一系列的blog主要是介绍银行会计的操作实务 希望为在初入银行的技术人员提供一些业务逻辑上的帮助 内容分为以下几个章节进行分析 银行会计的基本理论和基本核算方法 人民币存款业务会计核算 人民币贷款业务核算 联行往来业务的核算
  • arcgis表转excel一直失败_Excel表转换为shp格式时属性值丢失问题

    早前在网上扒拉一些数据 放到excel中进行加工 然后加载到arcgis中 生成点要素 然后转为shp格式文件 但是在此过程中遇到了一些小问题 有些字段的信息在转换过程中会丢失 一开始我以为是我的excel编码的问题 但后来捣鼓了好多次 都
  • 区块链上的数据库:CovenantSQL

    引言 最近对区块链技术有一些兴趣 区块链技术估计这个名字已经被大家所熟知了 但区块链数据库估计还没几个人知道 目前国内有两种数据库RepChain 中科院研发 和CovenantSQL 本文讲重点讲解CovenantSQL 这一新兴区块链数
  • 超好用!分享8个 Python 自动化脚本

    每天你都可能会执行许多重复的任务 例如阅读新闻 发邮件 查看天气 打开书签 清理文件夹等等 使用自动化脚本 就无需手动一次又一次地完成这些任务 非常方便 而在某种程度上 Python 就是自动化的代名词 1 自动化阅读网页新闻 这个脚本能够
  • OLED拼接屏代工,如何选择靠谱的制造商?

    OLED拼接屏代工是一种新型的显示技术 它采用有机发光二极管 OLED 作为显示元件 具有高亮度 高对比度 高色彩饱和度 快速响应 低功耗等优点 被广泛应用于电视 手机 平板电脑 汽车显示屏等领域 而OLED拼接屏则是将多个OLED屏幕拼接
  • svm通俗讲解_通俗易懂--SVM算法讲解(算法+案例)

    1 SVM讲解 SVM是一个很复杂的算法 不是一篇博文就能够讲完的 所以此篇的定位是初学者能够接受的程度 并且讲的都是SVM的一种思想 通过此篇能够使读着会使用SVM就行 具体SVM的推导过程有一篇博文是讲得非常细的 具体链接我放到最后面
  • 校园贷受阻,汽车分期能帮趣店挽救困局吗?

    随着新零售理念被提出 众多传统零售领域均发生了颠覆式的零售革命 传统便利店到无人零售等新零售模式所获得的成功 更是激起了其他领域对新零售理念的热捧与追随 2018年1月中旬 以校园分期贷为主营业务的趣店 在上市之后又对外宣布将进军汽车新零售
  • Camera.WorldToScreenPoint 世界转屏幕位置

    Camera WorldToScreenPoint 世界转屏幕位置 function WorldToScreenPoint position Vector3 Description描述 Transforms position from wo
  • 7.TensorRT中文版开发教程-----TensorRT中的INT8量化详解

    7 如何使用TensorRT中的INT8 点击此处加入NVIDIA开发者计划 7 1 Introduction to Quantization TensorRT 支持使用 8 位整数来表示量化的浮点值 量化方案是对称均匀量化 量化值以有符号
  • 关于ActiveMq的持久化订阅

    1 ActiveMq 客户端
  • 央视国际节目定价发布接口规范C2

    央视国际 节目定价发布接口规范 V2 7 2 央视国际IP电视事业部 2011年3月 Revision History Revision Author Reviewed By A Description Of Change B Summar
  • ChatGPT可能马上取代你!ChatGPT能做什么?

    文章目录 前言 1 客服机器人 2 智能助手 3 内部沟通 4 个性化推荐 5 语音交互 6 教育培训 7 医疗健康 8 社交娱乐 9 营销推广 10 情感分析 11 舆情监测 12 知识管理 13 金融服务 14 物联网 15 公共服务
  • 【笔记】不一样的 双11 技术,阿里巴巴经济体云原生实践(下)

    CSE Serverless 在阿里巴巴 双11 场景的落地 云计算时代 Serverless 作为云原生重要技术组成部分 一开始便承载了太多的使命 承诺了云计算时代最典型并极具挑战的多维度服务指标 无服务运维 极速弹性伸缩 按量付费等 这
  • 关系数据库的特点

    关系数据库的特点 数据库管理系统将具有一定结构的数据组成一个集合 它主要具有以下几个特点 1 数据的结构化 数据库中的数据并不是杂乱无章 毫不相干的 它们具有一定的组织结构 属于同一集合的数据具有相似的特征 2 数据的共享性 在一个单位的各
  • .NET Core使用EF Core框架

    文章目录 概述 安装EF Core 使用EF Core增删改查 单表查询 插入数据 修改数据 删除数据 概述 Entity Framework EF Core 是轻量化 可扩展 开源和跨平台版的常用 Entity Framework 数据访
  • linux的用户和组

    linux是一个多用户 多任务的分时操作系统 windows是一个单用户操作系统 linux系统中的用户类型 1 root 超级管理员 uid 用户ID 0 权限大于Windows中的Administrator 2 系统用户 伪用户 uid
  • panda 修改行名字 报错 Index does not support mutable operations

    在进行panda数据操作 扩充时出现两个tricks 使用data pd append 进行行扩充数据时 行名需要相同 才能实现自动扩充 使用data pd columns 修改行名时 不允许切片操作 只能按照原数据长建立一个列表赋值修改
  • Python从txt文件中逐行读取数据

    非常的简单 提供三种方法 方法一 f open foo txt 返回一个文件对象 line f readline 调用文件的 readline 方法 while line print line 后面跟 将忽略换行符 print line e
  • 如何做好一份前端工程师的简历?

    一 你是前端工程师 虽然简历都会有一些常规信息 但职业决定了这份简历核心内容和求职成败 所以 这份简历应该尽可能体现你自己是一个合格的前端工程师 专业的前端工程师是什么可以看看去年Nate Koechley的演讲 Professional
  • 二叉树相关算法

    二叉树类算法 一 二叉树的路径和 二叉树的每个节点为0 9的一个数字 根到叶子的一条路径拼成一个数 求所有路径形成的数字和 struct TreeNode TreeNode left TreeNode right int value int