6、翻转二叉树:226. 翻转二叉树
分析:
我们直接在原来的树上面修改,先遍历这颗树,然后交换左右子树节点,遍历方式就选前序遍历
class Solution {
public:
TreeNode* invertTree(TreeNode* root)
{
if (root == NULL) return root;
swap(root->left,root->right); //遍历到了根节点
invertTree(root->left); // 左
invertTree(root->right); // 右
return root;
}
};
8、对称二叉树
先遍历左右子节点,然后比较之后将结果返回到上一层头节点间,后序
class Solution {
public:
bool compare(TreeNode* left, TreeNode* right) {
// 首先排除空节点的情况
if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
// 排除了空节点,再排除数值不相同的情况
else if (left->val != right->val) return false;
// 此时就是:左右节点都不为空,且数值相同的情况
// 此时才做递归,做下一层的判断
bool outside = compare(left->left, right->right); // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left); // 左子树:右、 右子树:左
bool isSame = outside && inside; // 左子树:中、 右子树:中 (逻辑处理)
return isSame;
}
bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
return compare(root->left, root->right);
}
};
9、树的最大深度
迭代法
1、二叉树的深度,根节点到任意一个节点的距离,中是我们的处理过程,往下一个就加上一,中、左、由前序遍历
2、二叉树的高度,尾端到任意一个节点的距离,下往上遍历,将结果返回给上一个节点,后序遍历
3、根节点的高度,就是最大深度
//深度一般是前序遍历,也就是根节点到任意一个节点的距离,
//最大深度是也是根节点的高度
class Solution {
public:
int maxDepth(TreeNode* root) {
return getheight(root);
}
int getheight(TreeNode*root){
if(root == nullptr) return 0;
int ledepth = getheight(root->left); //左
int ridepth = getheight(root->right); //右
int height = max(ledepth,ridepth) +1; //根节点比左右子节点高度加一,该结果会返回给根结点
return height;
}
};
层序遍历
分析:这个不就是求层数吗
-
树的深度:树内所有节点深度的最大值,也就是所有叶子节点深度的最大值,也就是树的层数
-
树的高度:树内所有节点高度的最大值,也就是根节点的高度,也就是树的层数
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*> que;//辅助队列
int nums = 0;
if(root != NULL) que.push(root);//头节点入栈
while(!que.empty())
{
int size = que.size();//记下每层元素个数
nums++;
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);
}
}
return nums;
}
};
10、最小深度
最小深度是从根节点到最近叶子节点的最短路径上的节点数量
叶子节点是没有子节点的节点
求最小深度与求高度的意思差不多,我们使用后序遍历简单点
//求深度一般是前序,但是比较麻烦,我们使用后序通过高度求深度逻辑是一样的
class Solution {
public:
int minDepth(TreeNode* root) {
return Getheight(root);
}
int Getheight(TreeNode* root)
{
if(root == NULL) return 0; //终止条件
int leftheight = Getheight(root ->left); //左
int rightheight = Getheight(root ->right); //右
//一个节点为空,一个节点不为空,根节点的高度就是不为空的节点的高度 +1
//下面是访问根节点也就中,一般都是通过return 访问到从子节点跳到根结点
if( root -> left == NULL && root ->right != NULL) return rightheight +1;
else if( root -> left != NULL && root ->right == NULL) return leftheight +1;
else//当节点都不为空的时候
{
return min(leftheight,rightheight) +1;
}
}
};
11、完全二叉树的节点个数
普通二叉树
直接使用后序遍历,先遍历左右节点的节点数,然后将统计结过上传到中节点
class Solution {
public:
int countNodes(TreeNode* root) {
return Getnums(root);
}
int Getnums(TreeNode* root){
if(root == NULL) return 0;//终止条件
int leftnums = Getnums(root ->left); //左
int rightnums = Getnums(root ->right);//右
int result = leftnums + rightnums +1;// 中 ,统计的数据传给中节点 +1,是加上了根及节点的
return result;
}
};
12、平衡二叉树
题目解析:
任意一个节点的左右子树的高度度差值不大于1
1、高度是距离最尾端叶子节点的距离(后序遍历,会向上返回结果)
使用递归的方法
后序遍历,先遍历左右节点是否满,然后将本层左右节点比较看是否满足条件
不满足条件的节点我们赋值-1,满足条件的我们会将高度赋值给他
给定一个二叉树,判断它是否是高度平衡的二叉树。
使用后序遍历先判断子节点然后返回到中节点
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
//使用递归的方法
class Solution {
public:
int Getheight(TreeNode* root){
if(root == NULL) return 0;//终止条件
int leftheight = Getheight(root ->left); //左
if(leftheight == -1) return -1;//将-1返回给左节点
int rightheight = Getheight(root ->right); //右
if(rightheight == -1) return -1;//将-1返回给右节点
//中
int res;
if(abs(leftheight - rightheight) > 1) //比较这一层的左右节点的值,讲结果返回给上一层
res = -1;
else
res = max(leftheight,rightheight) +1;//没有赋值的int,默认都是0
return res;
}
bool isBalanced(TreeNode* root) {
return Getheight(root) == -1 ? false:true;
}
};
15、左叶子之和
分析:
使用后序遍历,将我们结果上传
难点在怎么判断是左子叶,该结点是上一个节点的左结点,自己的左右节点都是空
//使用后序遍历,将我们结果上传
//难点在怎么判断是左子叶,该结点是上一个节点的左结点,自己的左右节点都是空
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
return Getsum(root);
}
int Getsum(TreeNode* root)
{
if(root == NULL) return 0;//终止条件
int leftnums = Getsum(root ->left); //左
if(root ->left != NULL && root ->left->left ==NULL && root ->left ->right == NULL)
leftnums =root ->left ->val;
int rightnums = Getsum(root ->right);//右
return leftnums + rightnums; //中
}
};
16、找树左下角的值
在树的最后一行找到最左边的值。
首先要是最后一行,然后是最左边的值
使用层序遍历很简单,每一层第一个就是最左边的
迭代法
//使用层序遍历简单,在每一层中左边都是先遍历的,把每一层的第一个第一都存放在一个变量中,最后剩下来的就是左下角的
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*>que;
if(root == NULL) return 0;
else 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;
}
};
19、最大二叉树
选择一个最大值作为根节点,然后从左边选择一个最大作为左子树节点,从右边选择最大构造右子树,然后一直循环下去,我们数组一直在变化
左子树区间 nums.begin(),nums.begin()+maxvalueindex )//左闭右开
右子树区间 nums.begin() + maxvalueindex +1,nums.end()
class Solution {
public:
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
TreeNode* node = new TreeNode(0);
if(nums.size() == 1) //当将数组中的最后一个值赋给了叶子节点就返回上一层
{
node ->val = nums[0];
return node;
}
//找到数组中的最大的值和对应的下标
int maxValue = 0;
int maxValueIndex = 0;
for(int i = 0; i < nums.size();i++){
if(nums[i] > maxValue){
maxValue = nums[i];
maxValueIndex = i;
}
}
node ->val = maxValue;//中
//根据最大值来构造左子树区间
if(maxValueIndex > 0){
vector<int> newVec(nums.begin(),nums.begin()+maxValueIndex);//重新构造左子树区间,左开右闭
node ->left = constructMaximumBinaryTree(newVec);//左
}
if(maxValueIndex < nums.size()-1){
vector<int> newVec(nums.begin()+maxValueIndex +1,nums.end());//重新构造右子树区间,左开右闭
node ->right = constructMaximumBinaryTree(newVec);//右
}
return node;//返回结果
}
};
21、合并二叉树
两个二叉树都有的节点就将二个数值相加,不然就补充进去作为新节点
疑问,我们是把以7为根节点的子树返回到上一层
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2;//终止条件,在我们发现有一方为空的时候就往上退
if (t2 == NULL) return t1;
// 重新定义新的节点,不修改原有两个树的结构
TreeNode* root = new TreeNode(0);
root->val = t1->val + t2->val; //中
root->left = mergeTrees(t1->left, t2->left);//左
root->right = mergeTrees(t1->right, t2->right);//右
return root;
}
};
22、二叉搜索树中的搜索
左子树节点比根节点小,右子树节点比根节点大
二叉搜索树是可以有序的,在中序排列的情况下就是递增的
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if (t1 == NULL) return t2;//终止条件,在我们发现有一方为空的时候就往上退
if (t2 == NULL) return t1;
// 重新定义新的节点,不修改原有两个树的结构
TreeNode* root = new TreeNode(0);
root->val = t1->val + t2->val; //中
root->left = mergeTrees(t1->left, t2->left);//左
root->right = mergeTrees(t1->right, t2->right);//右
return root;
}
};
23、验证二叉搜索树
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
- 中序为什么是越来越大,因为中序节点赋值是从底到顶实现赋值的,
不能只是单纯比较左节点小于中间节点,右边节点大于中间节点就完事了
我们要直接将每个节点的根存放在一个变量max中,每递归一次就会替换一次,但是现在只有下一个节点大于上一个才可以换,这样上面的根节点必须都要大于上一个根节点
class Solution {
public:
TreeNode* pre = NULL;//用来记录前一个节点
bool isValidBST(TreeNode* root) {
if(root ==NULL ) return true;//终止条件
bool leftvalue = isValidBST(root ->left);
if(pre != NULL && pre ->val >= root ->val) //我们这个赋值是自下而上的,所以后面是越来越大
{
return false;//跳上一层
}
pre = root;//结点更新
bool rightvalue = isValidBST(root ->right);
return leftvalue && rightvalue;
}
};
24、求二叉搜索树的最小绝对差值
class Solution {
private:
int result = INT_MAX;//存放绝对差
TreeNode* pre = NULL;
void traversal(TreeNode* cur) {
if (cur == NULL) return;//终止条件
traversal(cur->left); // 左
if (pre != NULL){ // 中
result = min(result, cur->val - pre->val);
}
pre = cur; // pre指针移动到下一个中点
traversal(cur->right); // 右
}
public:
int getMinimumDifference(TreeNode* root) {
traversal(root);
return result;
}
};
25、二叉搜索树中的众数
众数:出现频率最高的数
众数可以有多个
因为中序遍历的话中节点处理节点顺序就是按照从小到大,一样大小的数字都在附近
我们使用中序这样遍历就是按顺序的, pre指针指向上一个根节点,比较相邻根节点是否相同要是相同就count加一,使用一个变量存放count达到的最大值,要是达到最大值就这个root->val 存放到一个容器中,要是count超过了最大值就情况容器,然后将值插入容器中
class Solution {
public:
int maxCount = 0;//最大频率
int count = 0; //统计频率
TreeNode* pre = NULL;
vector<int> result;//存放结果
void searchBST(TreeNode* cur){
if(cur == NULL) return;
searchBST(cur ->left);//左
//中
if(pre == NULL) count = 1;//第一个节点
else if (pre ->val == cur ->val)//第二个节点与第一个节点相同
count ++;
else//节点与前一个不同
count = 1;//计数初始化
pre = cur;//pre指向当前节点,更新pre指针指向
if(count == maxCount)//如果和最大值相同,就放进result中
result.push_back(cur ->val);
if(count > maxCount)//计数大于最大值频率
{
maxCount = count; //更新最大频率
result.clear();//清空reslut容器
result.push_back(cur->val);
}
searchBST(cur ->right);
return;
}
vector<int> findMode(TreeNode* root) {
count = 0;
maxCount = 0;
TreeNode* pre = NULL;//记录前一个不同值的节点
result.clear();
searchBST(root);
return result;
}
};
26、二叉树最近的公共祖先
从后往上处理,两个汇聚到一个节点,就是公共祖先,故而使用后序遍历
root 遍历到目标节点就返回,最后中节点做处理,只有左右都找到才返回root,不然只返回我们找到的然后继续找,左右的那个root数据肯定是最后出现会覆盖left,right
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == q || root == p || root == NULL) return root;//遍历到目标或者空就返回,寻找祖先
TreeNode* left = lowestCommonAncestor(root ->left,p,q);//左
TreeNode* right = lowestCommonAncestor(root->right,p,q);//右
//中,处理逻辑
if(left != NULL && right != NULL) return root;//左右子节点都找到目标,将根节点返回
if(left != NULL && right == NULL) return left;//z只有左子节点找到,将左返回
else if(left == NULL && right != NULL) return right;//只有右子节点找到,将右返回
else
return NULL;
}
};
28、二叉搜索树的最近公共祖先
从后往上处理,两个汇聚到一个节点,就是公共祖先,故而使用后序遍历
只要发现一个根节点在这两个之间,就说明是最近公共祖先
//我们二叉搜索树比较特殊,直接前序就可以
class Solution {
public:
TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q)
{
if(cur == NULL) return cur;//遍历到底就返回
// 中不需要什么操作,只要等return 返回结果就好
//这个if可以直接确定搜索方向,都不需要要什么根、左、右
if(cur->val > p->val && cur ->val > q->val)//目标在根节点左子树
{
TreeNode* left = traversal(cur->left,p,q);
if(left != NULL) return left;//找到最近公共祖先
}
if(cur->val < p->val && cur ->val < q->val)//目标在根节点右子树
{
TreeNode* right = traversal(cur->right,p,q);
if(right != NULL) return right;
}
return cur;//代表找到
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return traversal(root,p,q);
}
};
29、二叉搜索树中的插入操作
位置都在叶子节点上
class Solution {
public:
TreeNode* parent;
void traversal (TreeNode* cur,int val){
if(cur == NULL)//找到空节点
{
TreeNode* node = new TreeNode(val);
if(val > parent ->val ) parent->right = node;
else
parent->left = node;
return;//返回上一级
}
parent = cur;//中
if(cur ->val >val) traversal(cur ->left,val);//左
if(cur ->val < val) traversal(cur ->right,val);//右
}
TreeNode* insertIntoBST(TreeNode* cur, int val) {
//当实空树,需要我们定义一下parent节点
parent = new TreeNode(0);
//当二叉树是空树的时候,直接创建一个节点就可以
if (cur == NULL) {
cur = new TreeNode(val);
}
traversal(cur,val);
return cur;
}
};