大家好!下面是我(一个小小的搬运工)在秋招的时候在Leetcode上整理的一些二叉树的题目(中等难度),笔试和面试考相似思路题目的概率比较大,大家如果准备春秋季招聘可以先根据这些题目复习(具体思路可以看Leetcode中的讲解——困难的题有链接):

//2019_04_27// 定义二叉树结构
struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}};//1、层序遍历二叉树  用一个vector存储每一层的数值,另一个vector<vector> 存储所有的class Solution {
public:vector<vector<int> > levelOrder(TreeNode *root) {vector<vector<int>>result;queue<TreeNode*>current, next;if (root == nullptr)return result;current.push(root);while (!current.empty()){vector<int>level;while (!current.empty()){TreeNode* node = current.front();current.pop();level.push_back(node->val);if (node->left != nullptr)next.push(node->left);if (node->right != nullptr)next.push(node->right);}result.push_back(level);swap(current, next);}return result;}
};//2019_05_03//1、给定一个数组(扩展:若数组无序则可先进行排序),其中元素按升序排序,将其转换为高度平衡的二叉搜索树
/** 这道题是二分查找树的题目,要把一个有序数组转换成一颗二分查找树。* 从本质来看,如果把一个数组看成一棵树(也就是以中点为根,左右为左右子树,依次下去)* 数组就等价于一个二分查找树。* 所以如果要构造这棵树,那就是把中间元素转化为根,然后递归构造左右子树。* 所以我们还是用二叉树递归的方法来实现,以根作为返回值,每层递归函数取中间元素,* 作为当前根和赋上结点值,然后左右结点接上左右区间的递归函数返回值。* 时间复杂度还是一次树遍历O(n),* 总的空间复杂度是栈空间O(logn)加上结果的空间O(n),额外空间是O(logn),总体是O(n)。*/
class Solution {
public:TreeNode *tobst(vector<int > &num,int pre,int post){if(pre==post)return NULL;int mid=(pre+post)/2;           //int mid=left+(right-left+1)/2;(可防止溢出)TreeNode *root=new TreeNode(num[mid]);root->left=tobst(num,pre,mid);root->right=tobst(num,mid+1,post);return root;}TreeNode *sortedArrayToBST(vector<int> &num) {return tobst(num,0,num.size());}
};//2、给定一棵二叉树,判断其是否镜像对称(即镜像二叉树)  警告:不能用中序遍历来判断{1,2,3,3,#,2,#}
class Solution {
public:bool isSymmetric(TreeNode *root) {return solv( root, root );}bool solv( TreeNode* p1, TreeNode* p2 ){if( !p1 && !p2 )return true;else if( !p1 )return false;else if( !p2 )return false;if( p1->val != p2->val )return false;elsereturn solv(p1->left, p2->right) && solv(p1->right, p2->left);}
};//2019_05_07//1、定义一棵多叉树,并进行深度优先遍历和广度优先遍历  (广联达面试——设计一个文件系统,并且打印出文件名)   深度遍历代码可能有问题!!!class Node {                                      //多叉树的定义!!!    常用于文件系统!!!
public:int val;vector<Node*> children;Node() {}Node(int _val, vector<Node*> _children) {val = _val;children = _children;}
};class Solution {
public:vector<vector<int>> levelOrder(Node* root) {vector<int> res;vector<vector<int> > ans; bfs(root,res,ans);return ans;}void bfs(Node* root,vector<int> &res,vector<vector<int> > &ans){queue<Node*> tmp1;queue<Node*> tmp2;if(!root)return;Node* tmp;tmp1.push(root);while(!tmp1.empty()||!tmp1.empty()){while(!tmp1.empty()){tmp=tmp1.front();tmp1.pop();res.push_back(tmp->val);int k = tmp->children.size();int i=0;while(k--){tmp2.push(tmp->children[i++]); }}ans.push_back(res);res.clear();swap(tmp1,tmp2);}}};//2、判断两个二叉树是否相等
class Solution {
public:bool isSameTree(TreeNode *p, TreeNode *q) {if ((p == nullptr)&&(q == nullptr))return true;else if ((q == nullptr) || (p == nullptr))return false;else if (p->val != q->val)return false;return (isSameTree(p->left, q->left)&&isSameTree(p->right, q->right));}
};//2、判断一棵树是否是二叉搜索树
class Solution {
public:bool isValidBST(TreeNode *root) {if(root == NULL)return true;if(root->left)if(findRight(root->left)->val >= root->val)return false;if(root->right)if(findLeft(root->right)->val <= root->val)return false;return isValidBST(root->left)&&isValidBST(root->right);}TreeNode* findLeft(TreeNode *root){while(root->left){root=root->left;}return root;}TreeNode* findRight(TreeNode *root){while(root->right){root=root->right;}return root;}};//2019_05_09//1、将二叉树的每一层节点从左向右链接起来,每层的最后一个节点指向空节点struct TreeLinkNode {int val;TreeLinkNode *left, *right, *next;TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}};1 -> NULL/  \2 -> 3 -> NULL/ \    \4-> 5 -> 7 -> NULLclass Solution {
public:void connect(TreeLinkNode *root) {if(root==NULL) return;queue<TreeLinkNode*> que;que.push(root);while(!que.empty()){int n=que.size();for(int i=0;i<n;i++){TreeLinkNode* t=que.front(); que.pop();if(t->left!=NULL) que.push(t->left);if(t->right!=NULL) que.push(t->right);if(i<n-1) t->next=que.front();else t->next=NULL;}}}
};//2、给定一个二叉树,找一个从根节点到叶子结点和等于sum的路径
Given the below binary tree andsum = 22,5/ \4   8/   / \11  13  4/  \    / \7    2  5   1
return [ [5,4,11,2],[5,8,4,5] ]
方法1:(递归)
class Solution {
public:vector<vector<int> > pathSum(TreeNode *root, int sum) {vector<vector<int> > vv;vector<int> v;pathSum_Aux(root,sum,v,vv);return vv;}void pathSum_Aux(TreeNode* root,int sum,vector<int> v,vector<vector<int>>& vv){if(root == NULL)return;v.push_back(root->val);if(root->left == NULL && root->right == NULL && sum-root->val == 0){vv.push_back(v);}pathSum_Aux(root->left,sum-root->val,v,vv);pathSum_Aux(root->right,sum-root->val,v,vv);}
};
方法2:(回溯)
class Solution {
public:vector<vector<int> > pathSum(TreeNode *root, int sum) {vector<int> tmp;vector<vector<int>> res;if(root == NULL)return res;pathSumCore(root, res, tmp, sum);return res;}void pathSumCore(TreeNode *root, vector<vector<int>> &res, vector<int> &tmp, int sum){if(root == NULL)return;if(root->val == sum && root->left == NULL && root->right == NULL){tmp.push_back(root->val);res.push_back(tmp);tmp.pop_back();return;}tmp.push_back(root->val);pathSumCore(root->left, res, tmp, sum - root->val);pathSumCore(root->right, res, tmp, sum - root->val);tmp.pop_back();}
};//2019_05_13
//1. 给定一棵二叉树,寻找其最大深度,即求二叉树的深度!
class Solution {
public:int maxDepth(TreeNode *root) {if (root == nullptr)return 0;int a = 0, b = 0;a = maxDepth(root->left);b = maxDepth(root->right);return max(a + 1, b + 1);}
};//2.给定一棵二叉树,判断其是不是高度平衡的二叉树
class Solution {
public:bool isBalanced(TreeNode *root) {if (root == NULL) { return true; }if (abs(maxDepth(root->left) - maxDepth(root->right)) > 1) {return false;}return isBalanced(root->left) and isBalanced(root->right);}int maxDepth(TreeNode *root) {if (root == NULL) { return 0; }return max(maxDepth(root->left), maxDepth(root->right)) + 1;}
};//2019_05_22
//1、给定一棵二叉树,寻找其根节点到叶子结点的和1/ \2   3
The root-to-leaf path1->2represents the number12.
The root-to-leaf path1->3represents the number13.Return the sum = 12 + 13 =25.//方法1:public int sumNumbers(TreeNode root) {int sum = 0;if (root == null) {return sum;}return preorderSumNumbers(root, sum);
}
public int preorderSumNumbers(TreeNode root, int sum) {if (root == null)return 0;sum = sum * 10 + root.val;if (root.left == null && root.right == null) {return sum;}return preorderSumNumbers(root.left, sum) + preorderSumNumbers(root.right, sum);/*
我觉得这个题目和剑指offer中的一道题目非常相似。先说这个题:
解题思路:从根结点开始,当每访问到一个结点,我们把该结点添加到路径上,并"累加"
该结点的值,这里"累加"的含义指的是按照题目的要求组成相应的数字即"左移"后相加。
如果该结点为叶结点,那么一条路径搜索完成,将当前所得结果累加。如果当前不是叶子
结点,则继续访问它 的子结点。当前结点访问结束后,递归函数将自动回到它的父结点。
因此我们在函数退出之前要在路径上"删除"当前结点,做法就是将当前路径值/10,以确
保返回父结点时路径刚好是从根结点到父结点的路径。我们不难看出保存路径的数据结构
实际上是一个栈,因为路径要与递归调用状态一致,而递归调用的本质就是一个压栈和出
栈的过程。
*///方法2:class Solution {
public:void sumNumbersCore(TreeNode *root, int &pathNum, int &sum) {if(root){pathNum = pathNum * 10 + root->val;//如果是叶子节点,一条路径搜索完成,累加到sumif(!root->left && !root->right){sum += pathNum;              }//如果不是叶子节点,则遍历它的子结点else{if(root->left)sumNumbersCore(root->left, pathNum, sum);if(root->right)sumNumbersCore(root->right, pathNum, sum);}//返回父结点之前,路径上“删除”当前节点pathNum /= 10;                    }}int sumNumbers(TreeNode *root) {int pathNum = 0;int sum = 0;sumNumbersCore(root, pathNum, sum);return sum;}
};//2、非递归进行二叉树的先序遍历
class Solution {
public:vector<int> preorderTraversal(TreeNode *root) {TreeNode *p=root;vector<int> res;stack<TreeNode *> ans;if(root==nullptr)return res;while(p||!ans.empty()){while(p){res.push_back(p->val);ans.push(p);p=p->left;}if (!ans.empty()){p = ans.top();ans.pop();p = p->right;}}return res;}
};//3、非递归进行二叉树的中序遍历
class Solution {
public:vector<int> inorderTraversal(TreeNode *root) {TreeNode *p=root;vector<int> res;stack<TreeNode *> ans;if(root==nullptr)return res;while(p||!ans.empty()){while(p){ans.push(p);p=p->left;}if (!ans.empty()){p = ans.top();res.push_back(p->val);ans.pop();p = p->right;}}return res;}
};
//3、非递归进行二叉树的后序遍历
//非递归做法, 后序遍历的麻烦在于访问过右子树之后,
//第二次访问的时候就必须访问根节点,而不是继续访问右子树
//所以使用pre来继续上次访问的节点
class Solution {
public:vector<int> postorderTraversal(TreeNode *root) {vector<int> ans;if(root == NULL) return ans;stack<TreeNode* > s;TreeNode * p = root;TreeNode * pre = NULL;//记录上次访问的节点while(p != NULL || !s.empty()) {while(p != NULL) {s.push(p);p = p->left;}if(!s.empty()) {p = s.top();s.pop();if(p->right == NULL || p->right == pre) {//右子树为空,或者是访问过ans.push_back(p->val);pre = p;//刚刚访问的右节点p = NULL;}else {s.push(p);p = p->right;}}}return ans;}
};//4、树的最小深度
class Solution {
public:int run(TreeNode *root) {int HR,HL,MAXH;if(root){int HR=run(root->right);int HL=run(root->left);if(HR!=0&&HL!=0)MAXH=HR<HL?HR:HL;else if(HR==0)MAXH=HL;elseMAXH=HR;return MAXH+1;}elsereturn 0;}
};//2019_05_28
给定一个二叉树,原地将它展开为链表。例如,给定二叉树1/ \2   5/ \   \
3   4   6
将其展开为:1\2\3\4\5\6class Solution {
public:void flatten(TreeNode* root) {if (root == nullptr){return;}flatten(root->left);                       //先将左子树展开flatten(root->right);                      //再将右子树展开//将展开后的左子树作为root的右子树//将展开后的右子树作为新右子树的右子树TreeNode* r = root->right;root->right = root->left;root->left = nullptr;                    //注意置为NULLwhile (root->right != nullptr){root = root->right;}root->right = r;}
};//2019_05_29
/*
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。示例 :
给定二叉树1/ \2   3/ \     4   5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。注意:两结点之间的路径长度是以它们之间边的数目表示
*/
/*** 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 res=0;//答案int dfs(TreeNode* p,int d){if(!p) return 0;//结束递归的条件int dl=dfs(p->left,d+1);//该节点左子树高度int dr=dfs(p->right,d+1);//该节点右子树高度res=max(res,dr+dl);//此次递归该做的事return max(dl,dr)+1;//此次递归返回的该节点高度}int diameterOfBinaryTree(TreeNode* root) {dfs(root,0);return res;}
};/*
不一定经过根节点的路径最长!!!!!!!!!!
class Solution {
public:int diameterOfBinaryTree(TreeNode* root) {if(!root)return 0;if(!root->left&&!root->right)return 0;int left=finddepth(root->left);int right=finddepth(root->right);return left+right;}int finddepth(TreeNode* root){if(!root)return 0;int left=finddepth(root->left);int right=finddepth(root->right);return max(left,right)+1;}
};
*///2019_05_31
/*
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。输入: Tree 1                     Tree 2                  1                         2                             / \                       / \                            3   2                     1   3                        /                           \   \                      5                             4   7
输出:
合并后的树:3/ \4   5/ \   \ 5   4   7
*/
class Solution {
public:TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {if(!t1)return t2;if(!t2)return t1;TreeNode* res=new TreeNode(t1->val+t2->val);res->left=mergeTrees(t1->left,t2->left);res->right=mergeTrees(t1->right,t2->right);return res;}
};//2019_06_02
/*
翻转一棵二叉树。示例:输入:4/   \2     7/ \   / \
1   3 6   9
输出:4/   \7     2/ \   / \
9   6 3   1
*/
class Solution {
public:TreeNode* invertTree(TreeNode* root) {if(!root)return nullptr;invertTree(root->left);invertTree(root->right);TreeNode* tmp=root->left;root->left=root->right;root->right=tmp;return root;}
};//2019_06_03
/*
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。例如:输入: 二叉搜索树:5/   \2     13输出: 转换为累加树:18/   \20     13
*/
//非递归解法
class Solution {
public:
private:stack<TreeNode*> all;void traversal(TreeNode* root){if(!root) return;if(root->left) traversal(root->left);all.push(root);if(root->right) traversal(root->right);}
public:TreeNode* convertBST(TreeNode* root) {if(!root) return 0;traversal(root);int s=0;while(!all.empty()){s+=all.top()->val;all.top()->val=s;all.pop();}return root;}};
//递归解法(以右->根->左的顺序遍历二叉树,将遍历顺序的前一个结点的累加值记录起来,和当前结点相加,得到当前结点的累加值)
class Solution {
public:int per = 0;TreeNode* convertBST(TreeNode* root) {if (root == NULL) {return root;}convertBST(root->right);root->val += per;per = root->val;convertBST(root->left);return root;}
};//2019_06_05
/*
给定一个非空二叉树,返回其最大路径和。本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。示例 1:输入: [1,2,3]1/ \2   3输出: 6
示例 2:输入: [-10,9,20,null,null,15,7]-10/ \9  20/  \15   7输出: 42
*//*对于任意一个节点, 如果最大和路径包含该节点, 那么只可能是两种情况:
1. 其左右子树中所构成的和路径值较大的那个加上该节点的值后向父节点回溯构成最大路径
2. 左右子树都在最大路径中, 加上该节点的值构成了最终的最大路径*/class Solution {
public:
int maxPathSum(TreeNode* root) {if(root == NULL)return 0;int ans = INT_MIN;MaxSum(root,ans);return ans;}int MaxSum(TreeNode* root, int& ans){if(root == NULL)return 0;//如果子树路径和为负则应当置0表示最大路径不包含子树int left = max(0,MaxSum(root->left,ans));  int right = max(0,MaxSum(root->right,ans));//以当前节点为根节点,判断在该节点包含左右子树的路径和是否大于当前最大路径和ans = max(ans, left+right+root->val);       //当左右都为负值时,返回中间值//当前节点作为父节点的一个子节点和父节点连接的话则需取【单端的最大值】返回return max(left+root->val,right+root->val);}
};//2019_06_17
// 1.给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)
class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {vector<int> res1;vector<vector<int>> res2;queue<TreeNode*> ans1;queue<TreeNode*> ans2;if(!root)return res2;ans1.push(root);int count=1;                    //用来判断是奇数行还是偶数行while(!ans1.empty()||!ans2.empty()){res1.clear();while(!ans1.empty()){TreeNode* mid=ans1.front();ans1.pop();res1.push_back(mid->val);if(mid->left)ans2.push(mid->left);if(mid->right)ans2.push(mid->right);}swap(ans1,ans2);if(count%2==1)res2.push_back(res1);else{reverse(res1.begin(), res1.end());res2.push_back(res1);}count++;}return res2;}
};//2019_07_02
/*
序列化和反序列化二叉搜索树————————不能采用中序遍历,因为会丢失根节点信息!!!(即转换的二叉搜索树不唯一)
*/
/*
二叉查找树/二叉排序树/二叉搜索树,对于一个node,左子树均小于等于node,右子树均大于等于node,
中序遍历是排序好的的数据,对于二叉排序树有插入一个元素BST_insert和查找一个元素BST_search的操作
想法:将二叉排序树前序遍历存储到vector,再重新插入元素构造就可以得到和原来一模一样的树,
这里一定是前序遍历,因为中左右,还有插入元素算法的原理,才是先从root开始
本题思想:
编码:先画一个二叉搜索树,然后前序遍历形式,将整型数据转化为字符串并且用特殊符号连接。比如8#3#1#6#
解码:根据分隔符,将数字拆分出来,然后第一个数字作为root,在依次插入即可
补充整形转字符串:
对于12345,可以利用对10取余,可以逐个的将个位取出,然后添加到str中,直到该数字%10为0,最后str反转即可
补充字符串转数字:
对于123#456#,val=0,for循环i,val = val*10+str[i]-'0',遇到#,打印val并且val清0
*/
/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
void change_int_to_string(int val, std::string &str_val){std::string tmp;while(val){//val每次循环都/10,因此循环valtmp += val % 10 + '0';//在字符0上作偏移val = val / 10;}//遍历val,每次将val个位转换为字符,添加到tmp尾部for(int i = tmp.length() - 1; i >= 0; i--){str_val += tmp[i];}//逆序str_val += '#';//转换每个数后加一个#
}void BST_preorder(TreeNode *node, std::string &data){if(!node){return;} //前序遍历递归跳出std::string str_val;change_int_to_string(node->val, str_val);data += str_val;//将每个节点转换为字符然后添加到dataBST_preorder(node->left, data);BST_preorder(node->right, data);
}void BST_insert(TreeNode *node, TreeNode *insert_node){//用来对于一个根,插入元素if (insert_node->val < node->val){//新元素小于根if (node->left){//如果有左子树,递归插入BST_insert(node->left, insert_node);}else{//无左子树,插在左边node->left = insert_node;}}else{//否则新元素大于等于根if (node->right){//如果有右子树,递归插入BST_insert(node->right, insert_node);}else{//否则插在右node->right = insert_node;}}
}class Codec {
public:// Encodes a tree to a single string.string serialize(TreeNode* root) {std::string data;//解码到dataBST_preorder(root, data);return data;}// Decodes your encoded data to tree.TreeNode* deserialize(string data) {if(data.length() == 0){return NULL;}//这是处理特殊情况,空树std::vector<TreeNode *> node_vec;int val = 0;//初始化node数组和val值for(int i = 0; i < data.length(); i++){//循环data提取所有节点值if(data[i] == '#'){//遇到#说明已经提取好了一个节点node_vec.push_back(new TreeNode(val));//这里不用delete,在类外delete析构即可,因为有rootval = 0;//node数组push并且val清0用于下次提取}else{val = val * 10 + data[i] - '0';//否则当前继续计算当前数字值}}for(int i = 1; i < node_vec.size(); i++){//还原二叉排序树,这里注意从1开始因为用到BST_insertBST_insert(node_vec[0], node_vec[i]);}return node_vec[0];}
};// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));//2019_07_03
/*
给定二叉树,按垂序遍历返回其结点值。对位于 (X, Y) 的每个结点而言,其左右子结点分别位于 (X-1, Y-1) 和 (X+1, Y-1)。把一条垂线从 X = -infinity 移动到 X = +infinity ,每当该垂线与结点接触时,我们按从上到下的顺序报告结点的值( Y 坐标递减)。如果两个结点位置相同,则首先报告的结点值较小。按 X 坐标顺序返回非空报告的列表。每个报告都有一个结点值列表。*/
class Solution
{
public:typedef map<int, vector<pair<int, int>>>  TT;         vector<vector<int>> verticalTraversal(TreeNode* root) {TT t;        //这里使用map而不是unordered_map,是为了利用map的关键字有序性质,map自动排序x轴vector<vector<int>> ans;dfs(root, 0, 0, t);for(auto &p : t){vector<int> temp;sort(p.second.begin(), p.second.end(), [](const pair<int, int> &lhs, const pair<int, int> &rhs){         //[]表示是匿名函数——https://www.cnblogs.com/pzhfei/archive/2013/01/14/lambda_expression.htmlreturn (lhs.first < rhs.first) || (lhs.first == rhs.first && lhs.second < rhs.second);});for(int i = 0; i != p.second.size(); ++i)temp.push_back(p.second[i].second);ans.push_back(temp);}return ans;}//x, y 代表当前节点的坐标void dfs(TreeNode *node, int x, int y, TT &t){if(node){t[x].push_back({y, node->val});dfs(node->left, x - 1, y + 1, t);dfs(node->right, x + 1, y + 1, t);}}
};
//2019_07_11
/*
1、给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
*/
/**注意p,q必然存在树内, 且所有节点的值唯一!!!递归思想, 对以root为根的(子)树进行查找p和q, 如果root == null || p || q 直接返回root表示对于当前树的查找已经完毕, 否则对左右子树进行查找, 根据左右子树的返回值判断:1. 左右子树的返回值都不为null, 由于值唯一左右子树的返回值就是p和q, 此时root为LCA2. 如果左右子树返回值只有一个不为null, 说明只有p和q存在与左或右子树中, 最先找到的那个节点为LCA3. 左右子树返回值均为null, p和q均不在树中, 返回null
**/class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {// 当 p,q 在分别在某个节点的左子树和右子树里,则该节点是最低公共祖先  if (!root || root == p || root == q) return root;auto left = lowestCommonAncestor(root->left, p, q);auto right = lowestCommonAncestor(root->right, p, q);if (left && right) return root;return left ? left : right;}
};/*
2、给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先
*/
/*首先回到问题本身:有两个点需要特别注意:(1) 二叉搜索树(排序特性);(2) 最近公共祖先,可以是本身。问题可以这样理解:(1) 如果节点在p、q节点之间或者节点与p或q相等,那么这种情况下,节点就为p、q的最近公共祖先;
(2) 如果p、q节点均小于节点,说明p、q在该节点的左子树,公共祖先在左子树中进行搜索;
(3) 如果p、q节点均大于节点,那么p、q在节点的右子树,公共最先在右子树中进行搜索;*/
class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//边界检测也是终止条件if(root==nullptr || p==nullptr || q==nullptr) return nullptr;//单步操作实现if((root->val<=q->val && root->val>=p->val)||(root->val<=p->val && root->val>=q->val))return root;//两种情况下返回值if(root->val>q->val && root->val>p->val){//2个节点均在左子树,由此在左子树中寻找最近公共节点return lowestCommonAncestor(root->left,p,q);}if(root->val<q->val && root->val<p->val){return lowestCommonAncestor(root->right,p,q);}return nullptr;}
};//2019_07_20
/**
给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?示例:输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:1         3     3      2      1\       /     /      / \      \3     2     1      1   3      2/     /       \                 \2     1         2                 3**//**
卡塔兰数作者:LeetCode
链接:https://leetcode-cn.com/problems/two-sum/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
**/class Solution {
public:int numTrees(int n) {vector<int> res(n+1,0);res[0]=1;res[1]=1;for(int i=2;i<=n;i++)for(int j=1;j<=i;j++)res[i]+=res[j-1]*res[i-j];return res[n];}
};//2019_07_27
/*
给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。示例:root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 810/  \5   -3/ \    \3   2   11/ \   \
3  -2   1返回 3。和等于 8 的路径有:1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11
*//*
1.最Naive的想法就是,以每个节点为根节点,都算一遍路径和为sum的有几条,然后加起来
*/
class Solution {public int pathSum(TreeNode root, int sum) {if(root == null) return 0;return helper(root, sum) + pathSum(root.left, sum) + pathSum(root.right, sum);}int helper(TreeNode root, int sum){if(root == null) return 0;sum -= root.val;return (sum == 0 ? 1 : 0) + helper(root.left, sum) + helper(root.right, sum);}
}/*
2.第一种做法很明显效率不够高,存在大量重复计算所以第二种做法,采取了类似于数组的前n项和的思路,比如sum[4] == sum[1],那么1到4之间的和肯定为0
对于树的话,采取DFS加回溯,每次访问到一个节点,把该节点加入到当前的pathSum中
然后判断是否存在一个之前的前n项和,其值等于pathSum与sum之差
如果有,就说明现在的前n项和,减去之前的前n项和,等于sum,那么也就是说,这两个点之间的路径和,就是sum最后要注意的是,记得回溯,把路径和弹出去
*/class Solution {
public:int pathSum(TreeNode* root, int sum) {unordered_map<int,int> res;res[0]=1;return helper(root,res,sum,0);}int helper(TreeNode* root, unordered_map<int,int> &res, int sum, int pathSum){if(!root)return 0;pathSum += root->val;int ans = res[pathSum - sum];++res[pathSum];ans += helper(root->left, res, sum, pathSum) + helper(root->right, res, sum, pathSum);--res[pathSum];return ans;}
};

秋招/春招常见笔试题目——二叉树系列(C/C++)相关推荐

  1. 在各大厂的秋招春招中,笔试面试都是必考的

    进修嵌入式须要那些内容? 数据构造与算法 这局部是程序员的必修课.在各大厂的秋招春招中,笔试面试都是必考的.常见的数据构造如链表,二叉树,堆,队列,常见排序算法及其改进(快排,归并,冒泡,插入)等都是 ...

  2. 研究生、本科生Java开发、后台、软件工程师秋招春招经验

    研究生.本科生Java开发.后台.软件工程师秋招春招经验 在2020年10月份的时候结束了自己的秋招过程.在秋招过程中,我也算是大厂中厂都拿过多个offer.在这个过程.在这半年的秋招过程中,通过自己 ...

  3. 2020届校招总结(秋招+春招)

    2020届校招总结(秋招+春招) 目录 个人情况 秋招 春招 总结 个人情况 末流211本科,通信工程专业,在实验室主要是做机器视觉和深度学习相关,实习在一家500强外企做数据挖掘,主要是在研究时序数 ...

  4. 【秋招/春招】投递岗位记录【快速法】

      除了投递以外,投递后秋招/春招进程的记录,也很重要,快速记录投递过程,进行信息检索与汇总,也是我们需要学会的能力.   以下介绍一下我自己个人记录的方法: Excel表格记录法 一.表格内容设计 ...

  5. 自己的秋招春招经历,现在的发展情况

    本人大四学生一枚,即将毕业,目前还未找到工作,说一下自己的秋招春招的经历. 秋招经历 由于个人的原因,在大三暑假的时候,自己并没有去找实习,这里就缺少了以后在就职过程中的一个加分的点.在2019年9月 ...

  6. 校招/社招/秋招/春招求职指南

    秋招.春招 1.招聘人数:秋招多余春招 2.招聘时间:秋招一般7月开始,大概一直延续到10月底,但是大厂(BAT)都会开始的很早:春招最佳的时间在3月,次佳是在4月,进入5月基本上就很少了. 3.难度 ...

  7. 互联网大厂笔试都考什么题?最新各大厂秋招春招实习笔试题合集【持续更新...】

    本文整理网上的大厂笔试题.主要是让读者可以感受一下各个厂的笔试难度! 如有侵权,请私信删除! 文章目录 一.阿里巴巴 1. 2022最新阿里实习笔试试题 单选 不定项 算法题 1. 2021阿里实习笔 ...

  8. 2023河南土著双非硕士——毕业季秋招春招就业经验分享(仅限于在河南找工作,毕业想留河南)

           作为一名河南土生土长的人,本硕皆就读于河南某双非一本,是一个实打实的河南土著,河南作为互联网就业的贫困环境,相较于CSDN博客上那么多动不动就腾讯.阿里.字节等大厂的就业经验分享,我更想 ...

  9. 菜鸟已OC(秋招春招找工作经历分享)

    找工作经历总结 & 菜鸟OC 1. 题外话(自我总结) 2. 菜鸟OC 1. 题外话(自我总结) 回顾去年的整个秋招过程,是心累且痛苦的. 首先,在去年上半年,经历了许多事情让我压力倍增:小论 ...

最新文章

  1. java进制转化_【Java学习笔记之四】java进制转化
  2. 前端代码规范(es6,eslint,vue)
  3. http请求 get 与 post 区别
  4. top进阶命令htop运用
  5. 做好MSSQL保卫战之xp_cmdshell
  6. C++设计模式之三 单例模式
  7. c语言编程从键盘上输入两个整数m和n,C语言习题 求键盘输入的两个正整数的最大公约数和最小公倍数...
  8. vb中调用aspx页面
  9. jquery中的ready函数与window.onload谁先执行
  10. python输出文字和数字加法_用c语言或者python将文件中特定字符串后面的数字相加...
  11. Selenium 对元素element的操作举例
  12. 小学六年级学生写的 “线段树”解析,厉害了!
  13. mysql odb驱动_odb C++访问mysql数据库,从安装到写入
  14. 如何解决pycharm下载库总是失败?
  15. SpringBoot实现微信扫码登录功能让网站支持使用微信登录demo
  16. 【Python蓝桥杯】印章 共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。
  17. 实验三+126+黄晟
  18. Maven项目插件飘红解决方案
  19. arduino使用晶联讯jlx12864
  20. 不懂就学——什么是input和output?

热门文章

  1. react 监听键盘事件及多按键事件
  2. S7-200SMART PLC的IP更改方法
  3. 网易云IM Flutter版本来啦,需要的拿去用。
  4. TensorFlow基础学习
  5. 中国移动位置服务基地能力开放平台
  6. IDEA alt + insert快捷键不能使用
  7. 成都宏鑫软科技有限公司
  8. Java读取Excel中的合并单元格
  9. java模拟京东登陆_requests+beautifulsoup模拟登陆京东
  10. el-input 纯数字输入 限制长度 限制最大值方法