二叉树属性
Leetcode.101.对称二叉树
101. 对称二叉树 - 力扣(LeetCode) (leetcode-cn.com)
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
1
/
2 2
/ \ /
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
/
2 2
\
3 3
进阶:
你可以运用递归和迭代两种方法解决这个问题吗?
思路:
递归思路:首先我们如何确定这个二叉树对称,就是它的左右子树对称(外侧值等于外侧值,内侧值等于内侧值)。接下来就是写出递归函数,抓住递归函数三要素:返回类型与参数【我们比较的是两个节点所以我们传入的是节点,返回的就是bool值】;终止条件【在比较的时候我们要先排除空节点的情况,有3中情况:右空,左空,双空。在排除一种清空,双有,且值不相等】;单层循环逻辑【接下来就是递归的主要逻辑,我们在递归函数中,继续比较左节点的右节点与右节点的左节点,右节点的右节点与左节点的左节点的大小】
class Solution {
public:
bool compare(TreeNode* left,TreeNode* right){
if(left&&right&&(left->val!=right->val))return false;
else if(!left&&right)return false;
else if(left&&!right)return false;
else if(!left&!right)return true;
else compare(left->left,right->right)&&compare(left->right&&right->left);
}
bool isSymmetric(TreeNode* root) {
if(root==nullptr)return true;
return compare(root->left,root->right);
}
};
迭代思路:
我们将两个节点的值放入队列进行判断比较
class Solution {
public:
bool isSymmetric(TreeNode* root) {
queue<TreeNode*>que;
if(root==NULL)return true;
que.push(root->left);
que.push(root->right);
while(!que.empty()){
TreeNode* leftnode=que.front();que.pop();
TreeNode* rightnode=que.front();que.pop();
if(!leftnode&&!rightnode){
continue;
}
if(!leftnode||!rightnode||(leftnode->val!=rightn->val)){
return false;
}
que.push(leftnode->left);
que.push(rightnode->right);
que.push(leftnode->right);
que.push(rightnode->left);
}
return true;
}
};
Leetcode.100.相同的树
给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
实例一:
输入:p = [1,2,3], q = [1,2,3]
输出:true
实例二:
输入:p = [1,2], q = [1,null,2]
输出:false
c++源码
class Solution {
public:
bool compare(TreeNode*root1,TreeNode*root2){
if(root1==nullptr&&root2!=nullptr)return false;
else if(root1!=nullptr&&root2==nullptr)return false;
else if(root1==nullptr&&root2==nullptr)return true;
else if(root1!=nullptr&&root2!=nullptr&&(root1->val!=root2->val))return false;
else {
return compare(root1->left,root2->left)&&compare(root1->right,root2->right);
}
}
bool isSameTree(TreeNode* p, TreeNode* q) {
return compare(p,q);
}
};
Leetcode.572.另一个树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false
//实现代码:
class Solution {
public:
bool compare(TreeNode*r,TreeNode*s){
if(r==nullptr&&s!=nullptr)return false;
else if(r!=nullptr&&s==nullptr)return false;
else if(r==nullptr&&s==nullptr)return true;
else if(r!=nullptr&&s!=nullptr&&(r->val!=s->val))return false;
bool bo1=compare(r->left,s->left);
bool bo2=compare(r->right,s->right);
bool com=bo1&&bo2;
return com;
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root==nullptr)return false;
if(subRoot==nullptr)return true;
return compare(root,subRoot)||isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}
};
Leetcode.104.二叉树的最大深度
104. 二叉树的最大深度 - 力扣(LeetCode) (leetcode-cn.com)
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回它的最大深度 3 。
思路:在[上一篇文章]((10条消息) 【精选高频面试题】二叉树遍历合集_Sefr后端-CSDN博客)中我们用到了迭代法-层序遍历的方式来求得其最大深度。因为层数=深度。在这篇文章中我们使用递归法。
class Solution {
public:
int getdepth(TreeNode*root){
if(root==nullptr)return 0;
int leftdepth=getdepth(root->left);
int rightdepth=getdepth(root->right);
int depth=1+max(leftdepth,rightdepth);
return depth;
}
int maxDepth(TreeNode* root) {
int depth=getdepth(root);
return depth;
}
};
递归法:
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*>que;
int count=0;
if(root!=nullptr)que.push(root);
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;i++){
TreeNode*node=que.front();
que.pop();
if(node->left)que.push(node->left);
if(node->right)que.push(node->right);
}
count+=1;
}
return count;
}
};
Leetcode.559.N叉树的最大深度
559. N 叉树的最大深度 - 力扣(LeetCode) (leetcode-cn.com)
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
输入:root = [1,null,3,2,4,null,5,6]
输出:3
//思路一:迭代法-层序遍历
class Solution{
public:
int maxDepth(Node* root){
queue<Node*>que;
if(root!=NULL)que.push(root);
int depth=0;
while(!que.empty()){
int size=que.size();
depth++;
for(int i=0;i<size;i++){
Node* node=que.front();
que.pop();
for(int j=0;j<node->children.szie();j++){
if(node->children[j])que.push(node->children[j]);
}
}
}
return depth;
}
};
//递归法
class Solution{
int maxDepth(Node*root){
if(root==0)return 0;
int depth=0;
for(int i=0;i<root->children.size();i++){
depth=max(depth,maxDepth(root->children[i]));
}
}
};
Leetcode.111.二叉树的最小深度
111. 二叉树的最小深度 - 力扣(LeetCode) (leetcode-cn.com)
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
**说明:**叶子节点是指没有子节点的节点。
输入:root = [3,9,20,null,null,15,7]
输出:2
//迭代法-层序遍历
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*>que;
if(root!=nullptr)que.push(root);
int mindepth=0;
while(!que.empty()){
int size=que.size();
mindepth++;
for(int i=0;i<size;i++){
TreeNode*node=que.front();
que.pop();
if(node->left)que.push(node->left);
if(node->right)que.push(node->right);
if(!node->left&&!node->right)return mindepth;
}
}
return mindepth;
}
};
//`递归法
class Solution {
public:
int getdepth(TreeNode*root){
if(root==nullptr)return 0;
int leftdepth=getdepth(root->left);
int rightdepth=getdepth(root->right);
if(root->right!=nullptr&&root->left==nullptr){
return 1+rightdepth;
}
if(root->right==nullptr&&root->left!=nullptr){
return 1+leftdepth;
}//排除根节点的左节点或者右节点为空的情况。
int result=1+min(leftdepth,rightdepth);
return result;
}
int minDepth(TreeNode* root) {
int mindepth=0;
mindepth=getdepth(root);
return mindepth;
}
};
Leetcode.222.完全二叉树节点个数
222. 完全二叉树的节点个数 - 力扣(LeetCode) (leetcode-cn.com)
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
示例 1:
输入:root = [1,2,3,4,5,6]
输出:6
思路:普通二叉树做法(层序遍历+递归),完全二叉树做法(2^树深度-1)
做法一:层序遍历
class Solution {
public:
int countNodes(TreeNode* root) {
queue<TreeNode*>que;
if(root!=nullptr)que.push(root);
int number=0;
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;i++){
TreeNode*node=que.front();
que.pop();
number++;
if(node->left)que.push(node->left);
if(node->right)que.push(node->right);
}
}
return number;
}
};
做法二:递归
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==nullptr)return 0;
int numbers=0;
int leftnumber=countNodes(root->left);
int rightnumber=countNodes(root->right);
numbers=1+rightnumber+leftnumber;
return numbers;
}
};
做法三:完全二叉树的性质
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==nullptr)return 0;
TreeNode*left=root->left;
TreeNode*right=root->right;
int leftheight=0,rightheight=0;
while(left){
left=left->left;
leftheight++;
}
while(right){
right=right->right;
rightheight++;
}
if(rightheight==leftheight){
return (2<<leftheight)-1;
}
return countNodes(root->left)+countNodes(root->right)+1;
}
};
Leetcode.110.平衡二叉树
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
输入:root = [3,9,20,null,null,15,7]
输出:true
输入:root = [1,2,2,3,3,null,null,4,4]
输出:false
思路:这道题我们采用后序(左右中)的递归来解决。
第一:首先我们思考递归函数的返回值类型与参数类型:我们要获取这个节点的左右节点的高度来比较,所以我们返回int.参数类型为节点类型
第二:终止条件:什么时候停止递归?当节点为空的时候我们结束递归,也就是遍历到叶子节点的时候。
第三:单层遍历逻辑:我们要实现高度平衡,所以,| 左节点的高度-右节点的高度 |>1.当发生这种情况的时候我们就直接返回-1.表示这棵树不是平衡二叉树了。
class Solution {
public:
int depth(TreeNode*root){
if(root==NULL)return 0;
int leftdepth=depth(root->left);
if(leftdepth==-1)return -1;
int rightdepth=depth(root->right);
if(rightdepth==-1)return -1;
if(abs(leftdepth-rightdepth)>1){
return -1;
}
else{
return 1+max(leftdepth,rightdepth);
}
}
bool isBalanced(TreeNode* root) {
return depth(root)==-1?false:true;
}
};
class Solution {
public:
void trval(TreeNode*cur,vector<int>&path,vector<string>&res){
path.push_back(cur->val);
if(cur->left==nullptr&&cur->right==nullptr){
string Spath;
for(int i=0;i<path.size()-1;i++){
Spath+=to_string(path[i]);
Spath+="->";
}
Spath+=to_string(path[path.size()-1]);
res.push_back(Spath);
return;
}
while(cur->left){
trval(cur->left,path,res);
path.pop_back();
}
while(cur->right){
trval(cur->right,path,res);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string>res;
vector<int>path;
if(root==nullptr)return res;
trval(root,path,res);
return res;
}
};
Leetcode.257.二叉树的所有路径
给你一个二叉树的根节点 root
,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3,null,5]
输出:["1->2->5","1->3"]
思路:这道题因为要记录从上往下的路径所以我们要采用前序的递归法,同时使用了回溯的方法。
第一:确定返回类型以及参数。因为我们是要保存路径,所以不需要返回任何值->void;我们要设置一个vector来保存数值,同时用来回溯(pop_back())以及一个vector来保存结果.同时传入一个树节点
void traval(TreeNode* cur,vector<int>path,vector<string>result)
第二:终止条件:当我们的cur的左右节点都为空的时候那么就该终止,终止的逻辑就是把path中的内容转化为string保存到结果容器中
if(cur->left==NULL&&cur->right==NULL){
string Spath;
for(int i=0;i<path.size()-1;i++){
Spth+=to_string(path[i]);
spth+="->";
}
Spth+=to_string(path[path.size()-1]);
result.push_back(Spth);
return;
}
第三:单层遍历逻辑:因为要前序遍历我们要先处理中间的节点,添加进path.
path.push_back(cur->val)中
如果cur的左或者右节点存在的话,我们就继续往下迭代,直到不为空,同时我们要回溯
if(cur->left){
traval(cur->left,path,result);
path.pop_back();//回溯
}
if(cur->right){
traval(cur->left,path,result);
path.pop_back();//回溯
}
本题完整代码
class Solution {
public:
void trval(TreeNode*cur,vector<int>&path,vector<string>&res){
path.push_back(cur->val);//将根节点要先插入进去
if(cur->left==nullptr&&cur->right==nullptr){
string Spath;
for(int i=0;i<path.size()-1;i++){
Spath+=to_string(path[i]);
Spath+="->";
}
Spath+=to_string(path[path.size()-1]);
res.push_back(Spath);
return;
}
if(cur->left){
trval(cur->left,path,res);
path.pop_back();
}
if(cur->right){
trval(cur->right,path,res);
path.pop_back();
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string>res;
vector<int>path;
if(root==nullptr)return res;
trval(root,path,res);
return res;
}
};
Leetcode.404.左叶子节点之和
计算给定二叉树的所有左叶子之和。
示例:
3
/
9 20
/
15 7
在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
思路:本题采用前序迭代法和递归法。
//前序迭代法
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
stack<TreeNode*>st;
if(root==NULL)return 0;
st.push(root);
int result=0;
while(!st.empty()){
TreeNode*node=st.top();
st.pop();
if(root->left!=NULL&&root->left->left==NULL&&root->left->right==NULL){
result+=root->left->val;
}
if(root->left)st.push(root->left);
if(root->right)st.push(root->right);
}
return result;
}
};
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if(root==NULL)return 0;
int leftvalue=sumOfLeftLeaves(root->left);
int rightvalue=sumOfLeftLeaves(root->right);
int midvalue=0;
if(root->left!=NULL&&root->left->left==NULL&&root->left->right==NULL){
midvalue=root->left->val;
}
int sum=leftvalue+rightvalue+mvalue;
return sum;
}
};
Leetcode.513.找树左下角的值
513. 找树左下角的值 - 力扣(LeetCode) (leetcode-cn.com)
给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
输入: root = [2,1,3]
输出: 1
思路一:这道题采用层序遍历比较好理解,遍历到每一层,记录一下每一层的第一个节点的值即可。
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*>que;
if(root!=NULL)que.push(root);
int result=0;
while(!que.empty()){
int size=que.size();
for(int i=0;i<size;i++){
TreeNode*node=que.front();
que.pop();
if(i==0){
result=node->val;
}
if(node->left)que.push(node->left);
if(node->right)que.push(node->right);
}
}
return result;
}
};
思路二:递归。由于我们不知道该叶子节点是不是最大深度的叶子节点,所以我们需要回溯。
第一:返回类型与参数类型:我们首先需要设置两个全局变量,记录最大深度与最大深度的最左叶子节点值,每次遇到这个节点我们就更新一下最大深度值与最大深度,所以返回类型为void 参数类型为节点与最大深度
第二:终止条件:当我们遇到左叶子节点的时候我们就停止下来记录
第三:单层遍历逻辑:我们需要继续遍历这个节点的左节点和右节点,并同时回溯
class Solution {
public:
int maxleftlen=INT_MIN;
int maxleftvalue=0;
void leva(TreeNode*root,int lenmax){
if(root->left==NULL&&root->right==NULL){
if(lenmax>maxleftlen){
maxleftlen=lenmax;
maxleftvalue=root->val;
}
return ;
}
if(root->left){
lenmax++;
leva(root->left,lenmax);
lenmax--;
}
if(root->right){
lenmax++;
leva(root->right,lenmax);
lenmax--;
}
return;
}
int findBottomLeftValue(TreeNode* root) {
leva(root,0);
return maxleftvalue;
}
};
Leetcode.112.路径总和
112. 路径总和 - 力扣(LeetCode) (leetcode-cn.com)
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
**思路:**这道题我们使用递归法
第一:类型:我们需要判断是否存在这样的一条路径,且不需要搜索整棵二叉树,则需要返回值bool;
参数:如果我们对遍历的节点的值进行相加,则会比较复杂,要记录下来值,所以我们逆向思考,设置一个计数器,每次遇到一个节点我们就减去这个值,当计数器为0时就返回结果。所以我们参数为节点和一个计数器
第二:终止条件:当我们遍历到叶子节点的时候,且计数器为0的时候,就返回true;当遍历到叶子节点的时候,且计数器不为0,那么返回false;
第三:单层遍历逻辑:我们继续遍历root左右节点
class Solution {
public:
bool trval(TreeNode*root,int count){
if(!root->left&&!root->right&&count==0){
return true;
}
if(!root->left&&!root->right){
return false;
}
if(root->left){
if(trval(root->left,count-root->left->val))//回溯
return true;//如果找到了这个路径理解返回
}
if(root->right){
if(trval(root->right,count-root->right->val))//回溯
return true;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if(root==NULL)return false;
return trval(root,targetSum-root->val);
}
};
Leetcode.113.路径总和Ⅱ
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
这道题是要遍历整棵树所以不需要返回类型
class Solution {
public:
vector<int>path;//记录路径
vector<vector<int>>res;//记录结果
void trval(TreeNode*root,int count){
if(!root->left&&!root->right&&count==0){
res.push_back(path);
}
if(!root->left&&!root->right){
return;
}
if(root->left){
path.push_back(root->left->val);
trval(root->left,count-root->left->val);//回溯
path.pop_back(); //回溯
}
if(root->right){
path.push_back(root->right->val);
trval(root->right,count-root->right->val);//回溯
path.pop_back();//回溯
}
return ;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
path.clear();
res.clear();
if(root==NULL)return res;
path.push_back(root->val);
trval(root,targetSum-root->val);
return res;
}
};