LeetCode刷题day41

简介: LeetCode刷题day41

530. 二叉搜索树的最小绝对差

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

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

示例 1:


ff9a6bd68e7c421b812b3642f6ddbbb5.jpg

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

示例 2:

c220d6e92fae4da3a84531a0c611c47c.jpg

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

方法一—递归1

中序遍历得到二叉树的有序数组,然后寻找更新相邻两个数的差值

递归三部曲: 这个中序递归很简单,不再进行阐述.

参考代码1

vector<int> V;
int result = INT_MAX;
void traversal(TreeNode* node){
  if(node==NULL){
    return;
  }
  traversal(node->left);
  V.push_back(node->val);
  traversal(node->right);
} 
//递归法,中序遍历得到二叉树的有序数组.然后判断相邻两个数的差值.. 
int getMinimumDifference(TreeNode* root) {
  traversal(root);
  for(int i = 1;i < V.size();i++){
    result = min(result,V[i]-V[i-1]);
  }
  return result;
}

方法二—递归2

可以边遍历边进行寻找最小绝对差,只需要在中序遍历的时候,保存当前节点的上一个节点,

参考代码2

//递归法2:在递归过程中直接进行求解 
int result = INT_MAX; 
TreeNode* pre;
void traversal(TreeNode* node){
  if(node==NULL){
    return;
  }
  traversal(node->left);
  if(pre!=NULL){//第一个节点不用进行 min处理,因为没有前一个节点 
    result = min(result,node->val - pre->val)
  }
  pre = node; 
  traversal(node->right);
} 
int getMinimumDifference(TreeNode* root) {
  traversal(root);
  return result;
}

方法三—迭代

目前还不是很懂…

参考代码3

int getMinimumDifference(TreeNode* root) {
        stack<TreeNode*> st;
        TreeNode* cur = root;
        TreeNode* pre = NULL;
        int result = 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) {              // 中
                    result = min(result, cur->val - pre->val);
                }
                pre = cur;
                cur = cur->right;               // 右
            }
        }
        return result;
    }

501. 二叉搜索树中的众数


给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素)。

假定 BST 有如下定义:

结点左子树中所含结点的值小于等于当前结点的值

结点右子树中所含结点的值大于等于当前结点的值

左子树和右子树都是二叉搜索树


示例1

给定 BST [1,null,2,2],
   1
    \
     2
    /
   2
返回[2].


提示:如果众数超过1个,不需考虑输出顺序

方法一—普通二叉树

加入本题给的是一颗普通二叉树,那么可以采取如下的做法.

基本思路: 先把这个二叉树遍历了,用map来统计每个数出现的概率,最后按照概率进行排序,取概率最高的几个即可.

算法步骤:

  • 遍历整棵树,用map统计,可以使用前/中/后序都可.
unordered_map<int,int> map;
void searchBST(TreeNode* cur) {
  if(cur==NULL) {
    return;
  }
  map[cur->val]++;//统计元素频率
  searchBST(cur->left);
  searchBST(cur->right);
}

把统计出来的map数据,按照频率(也就是map中的value)排序.

由于map无法直接通过value进行排序,C++中可以使用map或者multimap对key排序,但就是不可以对value排序.

所以我们可以把map中的数据以pair<int,int>的形式放入到vector中,然后自定义规则进行排序.


//比较函数   --->自定义排序规则
bool cmp(const pair<int,int>& a,const pair<int,int>& b) {
  return a.second > b.second;
}
vector<pair<int,int>> vec(map.begin(),map.end());//由于在map中值是无法进行排序的.但我们可以将其放到vector中,自定义规则进行排序.
sort(vec.begin(),vec.end(),cmp);
  • 取前面的高频元素
    由于元素已经按照频率排完了序,所以只需要取前几个中最大的那几个即可.
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;
  }
}

参考代码1

//假如是一个普通二叉树
unordered_map<int,int> map;
void searchBST(TreeNode* cur) {
  if(cur==NULL) {
    return;
  }
  map[cur->val]++;//统计元素频率
  searchBST(cur->left);
  searchBST(cur->right);
}
//比较函数   --->自定义排序规则
bool 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 {};
  }
  searchBST(root);
  vector<pair<int,int>> vec(map.begin(),map.end());//由于在map中值是无法进行排序的.但我们可以将其放到vector中,自定义规则进行排序.
  sort(vec.begin(),vec.end(),cmp);
  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;
}

方法二—二叉搜索树的性质

二叉树的中序遍历是有序的

代码如下:

void searchBST(TreeNode* cur) {
    if (cur == NULL) return ;
    searchBST(cur->left);       // 左
    (处理节点)                // 中
    searchBST(cur->right);      // 右
    return ;
}

而如何在处理节点时候来获得众数呢?

我们可以使用pre和cur指针,这样每层处理时只需要比较pre==cur是否成立则可判断是否和前一个元素一样,进而可以统计该元素出现的频率.

初始化是pre=NULL,则count就为1了.

if (pre == NULL) { // 第一个节点
    count = 1; // 频率为1
} else if (pre->val == cur->val) { // 与前一个节点数值相同
    count++;
} else { // 与前一个节点数值不同
    count = 1;
}
pre = cur; // 更新上一个节点

但是题目要求的是求最大频率元素的集合,我们该如何做呢?


常规思路:先遍历一遍数组,找出最大频率maxCount,然后再重新遍历一遍数组,把出现频率为maxCount的元素放入到集合.

但是这个题我们可以遍历一遍就能实现目标.


思路:


如果元素频率count等于maxCount,则要把元素放入到集合中(这样肯定不保险了,万一后面出现更大的呢???),

之后判断count 是否大于maxCount.如果是 则不仅要更新maxCount,还要清空结果集(因为之前的结果集都失效了),放入当前元素.

//更新res和maxCount
if(count == maxCount) { //因为一旦这次的元素和上一次不同了,count=1,所以每一次count>=maxCount,res都必须要进行更新.
  res.push_back(cur->val);
} else if(count>maxCount) { //清空 res,想res中加入新的元素.更新maxCount.
  maxCount = count;
  res.clear();
  res.push_back(cur->val);
}

参考代码2

int maxCount;//最大频率
int count;//频率
vector<int> res;
TreeNode* pre = NULL;
void searchBST(TreeNode* cur) {
  if(cur==NULL) {
    return;
  }
  searchBST(cur->left);
  //中间节点的处理
  if(pre==NULL) {
    count==1;
  } else if(cur->val==pre->val) {
    count++;
  } else {
    count = 1;
  }
  //更新res和maxCount
  if(count == maxCount) { //因为一旦这次的元素和上一次不同了,count=1,所以每一次count>=maxCount,res都必须要进行更新.
    res.push_back(cur->val);
  } else if(count>maxCount) { //清空 res,想res中加入新的元素.更新maxCount.
    maxCount = count;
    res.clear();
    res.push_back(cur->val);
  }
  pre = cur;//更新上一个节点
  searchBST(cur->right);
}
vector<int> findMode(TreeNode* root) {
  if(root==NULL) {
    return {};
  }
  searchBST(root);
  return res;
}

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

方法一

思路:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。

使用后序遍历,回溯的过程就是从低向上遍历节点,一旦发现符合这个条件的节点,就是最近的公共节点了.


参考代码1


TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
  if(root==NULL||root == p || root == q){
    return root;
  }
  //遍历整棵树 
  TreeNode* left = lowestCommonAncestor(root->left,p,q);
  TreeNode* right = lowestCommonAncestor(root->right,p,q);
  if(left && right){
    return root;
  }else if(!left && right){//如果不再左子树,但在右子树则返回右子树节点. 
    return right;
  }else if(left && !right){//如果不在右子树,但在左子树则返回左子树节点. 
    return left;
  }
  return NULL;//如果都不再,则返回NULL; 
}
相关文章
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
61 6
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
54 4
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
124 2
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
40 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
4月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
70 7
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
54 5
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
31 4
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
Leetcode题目"剑指 Offer 21. 调整数组顺序使奇数位于偶数前面"的两种Python解决方案,一种是使用双端队列调整数组顺序,另一种是使用双指针法将奇数移到数组前半部分,偶数移到后半部分。
29 4