代码随想录day18 || 530二叉搜索树的绝对值 501二叉搜索树的众数 236二叉树的最近公共祖先

530二叉搜索树的绝对值 

力扣题目链接

题目描述:

给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

示例 1:

输入:root = [4,2,6,1,3]
输出:1

示例 2:

输入:root = [1,0,48,null,null,12,49]
输出:1

/*二叉搜索树的特点就是,中序遍历的时候是一个有序数组*/

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; // 记录前一个
    traversal(cur->right);  // 右
}
public:
    int getMinimumDifference(TreeNode* root) {
        traversal(root);
        return result;
    }
};

自己没好好读题,写了一个相邻最小差的:
代码:

class Solution {
public:
        int minn=INT_MAX;
        void findfuck(TreeNode* root){
             if(root->left==NULL&&root->right==NULL)return ;       
             if(root->left){getMinimumDifference(root->left);minn=min(minn,abs((root->val)-(root->left->val)));}
             if(root->right){getMinimumDifference(root->right);minn=min(minn,abs((root->val)-(root->right->val)));}
        }
    int getMinimumDifference(TreeNode* root) {  
        findfuck(root);
        return minn;
    }
};

501二叉搜索树的众数

力扣题目链接

题目描述:

给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

示例 1:

输入:root = [1,null,2,2]
输出:[2]

示例 2:

输入:root = [0]
输出:[0]

这个就用map来写,可以看之前的博客有对map的讲解

map<key,value>key是对应的值,value是这个值的价值(个数)

class Solution {
public:
    map<int,int> map;
    void searchBST(TreeNode* root){
        if(root==NULL)return;
        map[root->val]++;
        searchBST(root->left);
        searchBST(root->right);
    }
    bool static cmp (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;
        searchBST(root);
        vector<pair<int, int>> vec(map.begin(), map.end());
        sort(vec.begin(), vec.end(), cmp); // 给频率排个序
        result.push_back(vec[0].first);
        for (int i = 1; i < vec.size(); i++) {
            // 取最高的放到result数组中
            if (vec[i].second == vec[0].second) result.push_back(vec[i].first);
            else break;
        }
        return result;
    }
};

问题:

vector<pair<int, int>> vec(map.begin(), map.end());为什么这个vector是pair类型的,却可以放map类型的,为什么不定义为map类型的?

背景知识

  1. map 的结构:

    • map 是一个存储键值对的容器,其中每个元素都是一个 pair 类型的对象,包含一个键(key)和一个值(value)。在 map<int, int> 中,每个元素实际上是 pair<int, int> 类型。
    • 例如,map[5] = 10; 表示键为 5,值为 10 的一个 pair
  2. vector 的结构:

    • vector 是一个动态数组,能够存储多个元素,可以是任意类型,包括用户定义的类型。vector<pair<int, int>> 表示该 vector 中的每个元素都是 pair<int, int> 类型。

代码解释

在这一行 vector<pair<int, int>> vec(map.begin(), map.end()); 中:

  • map.begin() 和 map.end() 返回分别指向 map 开头和末尾的迭代器。
  • 当创建 vector<pair<int, int>> 时,使用的是 map 的迭代器初始化列表。这顺序地遍历 map 中的每个元素(即每个 pair<int, int>),并将它们添加到 vector 中。

为什么使用 vector<pair<int, int>>

使用 vector<pair<int, int>> 而不是 map 类型有以下原因:

  1. 默认操作:

    • map 设计用于快速查找,具有按键索引的特点,而 vector 是顺序容器,适合存储和操作一组数据。
    • 将 map 的内容放入 vector 中,可以对其进行灵活的排序和遍历操作。
  2. 排序:

    • vector 允许你方便地对元素进行排序(使用 sort() 函数)。map 自身是有序的,但是它不支持直接访问索引,比如要取第 n 个元素,必须通过迭代器遍历。
    • 在这段代码中,后面对 vec 进行了排序,以便于找到出现频率最高的元素。
  3. 简化处理:

    • 特定情况下,将键值对放入一个 vector 中可以更简化处理业务逻辑,例如找出最大频率的元素。

总结

vector<pair<int, int>> 用于存储来自 map 的所有键值对,以便进行排序和筛选操作。虽然直接使用 map 也是可以的,但这将使得后续操作变得繁琐(如排序和遍历)。因此,使用一个包含 pair 的 vector 在这个上下文中是更加简便和有效的选择。

236二叉树的最近公共祖先

力扣题目链接

题目描述:

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 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

代码:

class Solution {  
public:  
    // 定义一个函数,接收根节点 root 和两待查节点 p 和 q  
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {  
        // 如果当前节点为空,返回空节点  
        if(root == NULL) return root;  

        // 如果当前节点是 p 或 q,返回当前节点  
        if(root == p || root == q) return root;  

        // 递归查找左子树中 p 和 q 的最近公共祖先  
        TreeNode* left = lowestCommonAncestor(root->left, p, q);  
        
        // 递归查找右子树中 p 和 q 的最近公共祖先  
        TreeNode* right = lowestCommonAncestor(root->right, p, q);  

        // 如果左子树和右子树都找到了 p 或 q,则当前节点是最近公共祖先  
        if(left != NULL && right != NULL) return root;  

        // 如果左子树为空,返回右子树的结果(可能为 NULL 或找到的节点)  
        if(left == NULL && right != NULL) return right;  
        
        // 如果右子树为空,返回左子树的结果(可能为 NULL 或找到的节点)  
        else if(left != NULL && right == NULL) {  
            return left;  
        }  
        // 如果左右子树均为空,返回 NULL  
        else {  
            return NULL;  
        }  
    }  
};  

程序分析:

  1. 基本条件

    • 当 root 是 NULL 时,返回 NULL,这意味着树的某个部分已经被遍历到没有节点了。
    • 当 root 是 p 或 q 时,返回当前节点,这表明找到了其中一个目标节点。
  2. 递归遍历

    • 函数分别在左子树和右子树中查找 p 和 q,将结果存储在 left 和 right 中。
  3. 确定公共祖先

    • 如果 left 和 right 都非空,则说明 p 和 q 分别在当前节点的左侧和右侧,因此当前节点 (root) 是它们的最近公共祖先。
    • 如果只有一个子树找到了目标节点(即 left 或 right 中有一个非 NULL),则返回那个子树的结果,表明在那一边找到了目标节点;如果都没有找到,则返回 NULL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值