求二叉树的属性
Leetcode.700 二叉搜索树的搜索
700. 二叉搜索树中的搜索 - 力扣(LeetCode) (leetcode-cn.com)
给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。
例如,
给定二叉搜索树:
4
/ \
2 7
/ \
1 3
和值: 2
你应该返回如下子树:
2
/ \
1 3
在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。
思路:首先我们先了解一下二叉搜索树的性质:根节点左边的节点值始终小于根节点的值,根节点右边的节点的值始终大于根节点,所以我们可以根据这个性质来进行搜索。当搜索值大于节点值,那么就直接搜索节点值的右子树,反之搜索左子树。
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root==NULL||root->val==val)return root;
if(root->val>val) return searchBST(root->left,val);
if(root->val<val)return searchBST(root->right,val);
return NULL;
}
};
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
while(root!=NULL){
if(root->val>val)root=root->left;
else if(root->val<val)root=root->right;
else return root;
}
}
};
Leetcode.98.判断二叉搜索树
98. 验证二叉搜索树 - 力扣(LeetCode) (leetcode-cn.com)
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:root = [2,1,3]
输出:true
示例 2:
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。
**思路:**如果判断一个树是否是平衡二叉树?当一个节点的左子树的所有节点值要节点值,右子树的节点值要大于节点值。所以我们要比较左中右的节点值,所以我们要采用中序遍历。既然要比较,所以我们要初始化最小值用来更新最小值。【注意,在测试用例中,传入树的最小值为INT_MIN,所以我们要采用longlong min,但是 为了预防下一次测试用例采用longlong min ,我们就可以设置一个pre节点值为NULL,之后直接更新这个节点值】
//递归法
class Solution {
public:
TreeNode* pre=NULL;
bool isValidBST(TreeNode* root) {
if(root==NULL)return true;
bool left=isValidBST(root->left);
if(pre!=NULL&& root->val<=pre->val){
return false;
}
else{
pre=root;
}
bool right=isValidBST(root->right);
return left&&right;
}
};
//中序遍历迭代法
class Solution {
public:
bool isValidBST(TreeNode* root) {
stack<TreeNode*>st;
TreeNode* cur=root;
TreeNdoe* pre=NULL;
while(cur!=NULL||!st.empty()){
if(cur!=NULL){
st.push(cur);
cur->left;
}
else:{
cur=st.top();
st.pop();
if(pre!=NULL&&cur->val<=pre->val){
return false;
}
else{
pre=cur;
}
cur=cur->right;
}
}
return true;
}
};
Leetcode.530.二叉搜索树的最小绝对差
530. 二叉搜索树的最小绝对差 - 力扣(LeetCode) (leetcode-cn.com)
给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值。
示例:
输入:
1
3
/
2
输出:
1
解释:
最小绝对差为 1,其中 2 和 1 的差的绝对值为 1(或者 2 和 3)。
**思路:**当我们看到二叉搜索树的时候我们就要想到其性质:按中遍历输出是有序的,所以呢,方法一:我们就把这个搜索二叉树转换为有序数组,然后一一进行比较。
class Solution {
private:
vector<int>vec;
void trval(TreeNode*root){
if(root==NULL)return ;
if(root->left) trval(root->left);
vec.push_back(root->val);
if(root->right)trval(root->right);
}
public:
int getMinimumDifference(TreeNode* root) {
int result=INT_MAX;
trval(root);
for(int i=1;i<vec.size();i++){
result=min(result,vec[i]-vec[i-1]);
}
return result;
}
};
方法二:我们可以在遍历中直接比较,但是这个方法需要我们设置前一节点的指针。这个方法与98判断二叉树是否为平衡二叉树方法差不多,只是在处理中间节点的时候的操作逻辑不一样罢了
//递归
class Solution {
public:
int res=INT_MAX;
TreeNode*pre;
void trval(TreeNode* root){
if(root==nullptr)return ;
trval(root->left);
if(pre!=NULL){
res=min(res,root->val-pre->val);
}
pre=root;
trval(root->right);
}
int getMinimumDifference(TreeNode* root) {
trval(root);
return res;
}
};
//迭代
class Solution {
public:
int getMinimumDifference(TreeNode* root) {
stack<TreeNode*>st;
TreeNode* cur=root;
TreeNode* pre=NULL;
int res=INT_MAX;
while(cur!=NULL||!st.empty()){
if(cur!=NULL){
st.push(cur);
cur=cur->left;
}
else{
cur=st.top();
st.pop();
if(pre!=NULL){
res=min(res,cur->val-pre->val);
}
pre=cur;
cur=cur->right;
}
}
return res;
}
};
Leetcode.501.二叉搜索树中的众数
501. 二叉搜索树中的众数 - 力扣(LeetCode) (leetcode-cn.com)
给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。
假定 BST 有如下定义:
结点左子树中所含结点的值小于等于当前结点的值
结点右子树中所含结点的值大于等于当前结点的值
左子树和右子树都是二叉搜索树
例如:
给定 BST [1,null,2,2],
1
2
/
2
返回[2].
提示:如果众数超过1个,不需考虑输出顺序
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
**思路:**这道题有两种解法,第一种就是针对普通的二叉树,我们先遍历二叉树,将其结果使用哈希表存放,再将哈希表转化为vector,之后再对vector进行排序,再遍历vector获取最大值(众数)。第二种解法,是利用搜索二叉树的性质,中序遍历是有序的,将搜索二叉树按中序遍历,将相邻元素进行比较,记录其出现频率。
解法一:
class Solution {
public:
void trval(TreeNode*root,unordered_map<int,int>&map){
if(root==NULL)return ;
trval(root->left);
map[root->val]++;
trval(root->right);
return;
}
bool static com(const pair<int,int>&a,const pair<int,int>&b){
return a.second>b.second;
}
vector<int> findMode(TreeNode* root) {
vector<int>result;
if(root==NULL)return result;
unordered_map<int,int>map;
trval(root,map);
vector<pair<int,int>>vec(map.begin(),map.end());
sort(vec.begin(),vec.end(),com);
result.push_back(vec[0].first);
for(int i=1,i<vec.size();i++){
if(vec[i].second==vec.[0].second){
result.push_back(vec[i].first);
}
else break;
}
return result;
}
};
class Solution {
private:
int count;
int maxvalue;
TreeNode*pre;
vector<int>result;
void trval(TreeNode* cur){
if(cur==NULL)return;
trval(cur->left);//左
if(pre==NULL){
count=1;
}
else if(cur->val==pre->val){
count++;
}
else{
count=1;
}
if(maxvalue==count){
result.push_back(cur->val);
}
if(count>maxvalue){
maxvalue=count;
result.clear();
result.push_back(cur->val);
}
pre=cur;//中
trval(cur->right);//右
}
public: vector<int> findMode(TreeNode* root) {
count=0;
maxvalue=0;
pre=NULL;
if(root==NULL)return result;
trval(root);
return result;
}
};
Leetcode.236.二叉树的公共祖先
236. 二叉树的最近公共祖先 - 力扣(LeetCode) (leetcode-cn.com)
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
思路:首先我们如何判断某一节点是否为节点p,q的最近公共祖先,当这个节点的左子树是q,右子树是p,或者左子树为p,右子树为q的时候,则判断成功。
第二,我们采用后续遍历(回溯的过程)来判断节点的左右节点是否含有p,q,最终的结果传至根节点
递归3要素:
第一我们要确认函数的返回类型与参数,按道理是如果找到最小公共祖先的话就直接返回,但是我们还需要递归函数的返回值做逻辑处理,所以不能返回bool ,还是要返回节点值
第二终止条件:当传入节点的值等于p,或,q,或者空的时候return这个节点
第三:单层遍历逻辑:当左右节点都返回值的时候,说明找到了p,q,就返回这个节点值,当节点的左右值,一个为空,一个不为空的时候,就返回不为空的值。当节点的左右值都为空的时候就返回空
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==p||root==q||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 right;
else if(left!=NULL&&right==NULL)return left;
else{
return NULL;
}
}
};
Leetcode.235.搜索二叉树的最小公共祖先
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 输出: 6 解释: 节点 2 和节点 8 的最近公共祖先是 6。 示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4 输出: 2 解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉搜索树中。
思路:按照普通二叉树的做法,我们需要后续遍历整棵树。但是对于搜索二叉树,我们只需要从上往下的单边遍历就可以。因为搜索二叉树的性质,我们就可以确定遍历方向,二对于普通的二叉树,我们无法确定遍历方向。所以再对于这两种不同的树而言,单层遍历逻辑又不一样。具体看代码
class Solution {
public:
//返回类型:由于我们最后要返回祖先,所以类型为节点类型
TreeNode* trval((TreeNode* cur, TreeNode* p, TreeNode* q){
//如果没找到就返回空
if(cur==NULL)return root;
//根据搜索树的有序我们可以确定祖先的位置
if(cur->val>q->val&&cur->val>p->val){
TreeNode* left=trval(cur->left,p,q);
if(left!=NULL){
return left;//只要找到就返回,与普通的二叉树不一样
}
}
if(cur->val<p->val&&cur->val<q->val){
TreeNode* right=trval(cur->right,p,q);
if(right!=NULL){
return right
}
}
//如果cur的值位于p与q之间,说明就找到了祖先[一句搜索二叉树的性质]
return cur;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
return trval(root,p,q);
}
};
二叉树属性-系列一:https://blog.csdn.net/weixin_51325294/article/details/120268487