LeetCode 每周算法 8(栈、堆)

LeetCode 每周算法 8(栈、堆)

栈算法:

在这里插入图片描述

class Solution {  
public:  // 判断括号是否有效的函数  bool isValid(string s) {  int n = s.size(); // 获取字符串s的长度  // 如果字符串长度为奇数,则括号无法有效匹配,直接返回false  if (n % 2 == 1) {  return false;  }  // 创建一个哈希表(unordered_map),用于存储右括号到对应左括号的映射  unordered_map<char, char> pairs = {  {')', '('},  {']', '['},  {'}', '{'}  };  // 使用栈来辅助判断括号的匹配情况  stack<char> stk;  // 遍历字符串s中的每个字符  for (char ch : s) {  // 如果当前字符是右括号(即在pairs的键中存在)  if (pairs.count(ch)) {  // 如果栈为空,或者栈顶元素不是当前右括号对应的左括号,则括号无效,返回false  if (stk.empty() || stk.top() != pairs[ch]) {  return false;  }  // 如果栈顶元素是当前右括号对应的左括号,则从栈中弹出该左括号  stk.pop();  }  // 如果当前字符是左括号,则直接压入栈中  else {  stk.push(ch);  }  }  // 遍历完所有字符后,如果栈为空,则说明所有括号都有效匹配,返回true  // 如果栈不为空,则说明有未匹配的左括号,返回false  return stk.empty();  }  
};

在这里插入图片描述

class MinStack {  // 使用一个栈来存储元素,其中每个元素都是一个pair<int, int>  // pair的第一个元素是用户压入栈的值,第二个元素是当前栈中的最小值  stack<std::pair<int, int>> stk;  public:  // 构造函数,初始化一个空的栈  MinStack() {  }  // 将一个元素val压入栈中,并更新栈中的最小值  void push(int val) {  // 使用min函数比较当前val和栈顶的最小值,取两者中的较小者作为新的最小值  // 然后将这个值和val作为一个pair压入栈中  stk.push({val, std::min(val, getMin())});  }  // 弹出栈顶元素  void pop() {  stk.pop();  }  // 获取栈顶元素的值  int top() {  // 返回栈顶元素的第一个值,即用户压入栈的值  return stk.top().first;  }  // 获取栈中的最小元素  // 注意,这里使用了一个技巧:每次push时都更新栈顶元素为当前的最小值  // 因此,栈顶元素的第二个值总是当前栈中的最小值  int getMin() {  // 如果栈为空,则返回INT_MAX(表示没有最小值)  // 否则,返回栈顶元素的第二个值,即当前的最小值  return stk.empty() ? INT_MAX : stk.top().second;  }  
};/*** Your MinStack object will be instantiated and called as such:* MinStack* obj = new MinStack();* obj->push(val);* obj->pop();* int param_3 = obj->top();* int param_4 = obj->getMin();*/

在这里插入图片描述

class Solution {  
public:  // 存储待解码的原始字符串  string src;  // 用于在解码过程中跟踪当前处理的字符位置  size_t ptr;  // 辅助函数,用于连续读取并转换数字字符为整数  // 返回从当前ptr位置开始读取的数字,并将ptr移动到数字之后的第一个非数字字符  int getDigits() {  int res = 0; // 用于存储读取到的数字  // 循环直到ptr指向的字符不是数字或达到src的末尾  while (ptr < src.size() && isdigit(src[ptr])) {  // 将当前数字乘以10并加上新读取的数字字符(减去'0'转换为整数)  res = res * 10 + src[ptr++] - '0';  }  return res;  }  // 辅助函数,用于递归地解码字符串  // 它会根据括号、数字和字母的组合来构建并返回解码后的字符串  string getString() {  // 如果ptr已经到达src的末尾或遇到']',说明当前没有更多的字符可以解码,返回空字符串  if (ptr == src.size() || src[ptr] == ']') {  return "";  }  char cur = src[ptr]; // 当前处理的字符  int repTime = 1; // 重复次数,默认为1(如果没有显式指定)  string res; // 用于存储解码后的字符串  // 如果当前字符是数字,说明后面跟着的是重复次数  if (isdigit(cur)) {  repTime = getDigits(); // 读取并设置重复次数  ++ptr; // 移动ptr到'['之后  // 递归调用getString来解码括号内的字符串  string str = getString();  // 遇到']'表示括号内字符串结束,移动ptr到']'之后  ++ptr;  // 根据重复次数构建结果字符串  while (repTime--) res += str;  }   // 如果当前字符是字母,直接添加到结果字符串中,并移动ptr  else if (isalpha(cur)) {  res = string(1, src[ptr++]); // 将当前字母添加到结果字符串  }  // 继续递归解码剩余部分,并将结果与当前解码结果拼接  return res + getString();  }  // 主要的解码函数,初始化src和ptr,并调用getString开始解码过程  string decodeString(string s) {  src = s;  ptr = 0;  return getString(); // 返回解码后的字符串  }  
};

在这里插入图片描述

class Solution {  
public:  // 函数接收一个整数向量作为输入,返回一个整数向量作为输出  // 每个输出元素表示输入向量中对应元素后面第一个更高温度的天数差  // 如果没有更高的温度,则输出为0  vector<int> dailyTemperatures(std::vector<int>& temperatures) {  // 初始化一个与输入向量相同大小的答案向量,并将所有元素初始化为0  // 这表示默认情况下,我们还没有找到任何更高的温度  vector<int> answer;  answer.resize(temperatures.size(), 0);  // 使用一个栈来存储温度索引,栈顶是最近加入且尚未找到更高温度的温度索引  stack<int> s;  // 遍历输入的温度向量  for (int i = 0; i < temperatures.size(); i++) {  // 当栈不为空且当前温度大于栈顶索引对应的温度时  // 说明我们找到了栈顶索引对应温度的下一个更高温度  while (!s.empty() && temperatures[i] > temperatures[s.top()]) {  // 计算天数差(当前索引减去栈顶索引)并存储在答案向量中  answer[s.top()] = i - s.top();  // 弹出栈顶索引,因为它已经找到了下一个更高温度  s.pop();  }  // 将当前索引压入栈中,以便后续查找更高温度  s.push(i);  }  // 返回填充好的答案向量  return answer;  }  
};

在这里插入图片描述

class Solution {  
public:  int largestRectangleArea(vector<int>& heights) {  stack<int> s; // 使用一个栈来存储柱子的索引  int answer = 0; // 存储最大矩形面积  // 在heights数组的开始和结束各添加一个高度为0的柱子,这是为了方便处理边界情况  // 特别是当第一个柱子或最后一个柱子很高时,可以确保它们也能被正确处理  heights.insert(heights.begin(), 0);  heights.push_back(0);  // 栈的初始元素为第一个柱子的索引(即0,高度为0的柱子)  s.push(0);  // 遍历每个柱子的索引(从1开始,因为0是添加的辅助柱子)  for (int i = 1; i < heights.size(); i++) {  // 如果当前柱子的高度大于栈顶柱子的高度,直接入栈  if (heights[i] > heights[s.top()]) {  s.push(i);  }   // 如果当前柱子的高度等于栈顶柱子的高度,也入栈(这里其实可以优化为不入栈,因为等高的柱子不会影响面积计算)  else if (heights[i] == heights[s.top()]) {  s.push(i);  }   // 如果当前柱子的高度小于栈顶柱子的高度,说明找到了一个矩形的右边界  else {  while (heights[i] < heights[s.top()]) {  int mid = s.top(); // 栈顶柱子的索引,即当前矩形的“高”的柱子  s.pop(); // 弹出栈顶元素,因为我们已经找到了以它为高的矩形的右边界  // 计算矩形的宽度  // 如果栈为空,说明左边没有柱子,宽度为i;否则为i与栈顶柱子索引之差减1  int h = heights[mid]; // 矩形的高度  int w = i - s.top() - 1; // 更新最大面积  answer = max(answer, h * w);  }  // 将当前柱子的索引入栈,作为新的可能矩形的高度的起点  s.push(i);  }  }  // 遍历结束后,返回最大面积  return answer;  }  
};

在这里插入图片描述

class Solution {  
public:  int trap(vector<int>& height) {  // 创建一个栈来存储索引,而不是高度值  stack<int> s;  int sum = 0; // 用于记录总共接到的雨水量  // 栈中至少需要有一个元素作为起始边界,这里选择第一个元素作为起始  s.push(0);  // 从第二个元素开始遍历高度数组  for (int i = 1; i < height.size(); i++) {  // 如果当前元素的高度小于栈顶元素对应的高度,说明当前位置可能是一个水坑的一部分  // 将当前索引压入栈中,以便后续可能形成水坑时计算宽度  if (height[i] < height[s.top()]) {  s.push(i);  }   // 如果当前元素的高度等于栈顶元素对应的高度,同样压入栈中  // 这里其实可以优化,因为等高的元素不会增加新的水坑容量  else if (height[i] == height[s.top()]) {  s.push(i);  }   // 如果当前元素的高度大于栈顶元素对应的高度,说明找到了一个水坑的右边界  // 开始处理栈中存储的左边界到当前右边界之间的所有可能的水坑  else {  while (!s.empty() && height[i] > height[s.top()]) {  int mid = s.top(); // 当前处理的水坑的底部索引  s.pop(); // 弹出栈顶元素,即当前水坑的底部索引  // 如果栈不为空,说明存在左边界  if (!s.empty()) {  // 计算水坑的高度:左右边界中较低的高度减去当前水坑底部的高度  int h = min(height[s.top()], height[i]) - height[mid];  // 计算水坑的宽度:右边界索引减去左边界索引再减一(因为左右边界本身不计入宽度)  int w = i - s.top() - 1;  // 将当前水坑的容量加到总容量上  sum += h * w;   }  }  // 将当前元素(右边界)压入栈中,作为下一个可能水坑的左边界  s.push(i);  }  }  // 返回总共接到的雨水量  return sum;  }  
};

堆算法:

在这里插入图片描述

class Solution {
public:// int quickselect(vector<int> &nums, int l, int r, int k) {//     if (l == r)//         return nums[k];//     int partition = nums[l], i = l, j = r;//     while (i < j) {//         while (nums[i] < partition) i++;//         while (nums[j] > partition) j--;//         if (i < j)//             swap(nums[i], nums[j]);//     }//     if (k <= j) return quickselect(nums, l, j, k);//     else return quickselect(nums, j + 1, r, k);// }// int findKthLargest(vector<int>& nums, int k) {//     int n = nums.size();//     return quickselect(nums, 0, n - 1, n - k);// }// 将以i为根的子树调整为最大堆  void maxHeapify(vector<int>& a, int i, int heapSize) {  int l = i * 2 + 1; // 左子节点的索引  int r = i * 2 + 2; // 右子节点的索引  int largest = i;   // 假设当前根节点是最大的  // 如果左子节点存在且大于当前最大节点,则更新最大节点  if (l < heapSize && a[l] > a[largest]) {  largest = l;  }  // 如果右子节点存在且大于当前最大节点,则更新最大节点  if (r < heapSize && a[r] > a[largest]) {  largest = r;  }  // 如果最大节点不是根节点,则交换它们,并递归地调整受影响的子树  if (largest != i) {  swap(a[i], a[largest]);  maxHeapify(a, largest, heapSize);  }  }  // 从给定的无序数组构建最大堆  void buildMaxHeap(vector<int>& a, int heapSize) {  // 从最后一个非叶子节点开始向上构建最大堆  // 因为叶子节点不需要调整,且非叶子节点的索引为(heapSize/2)-1到0  for (int i = heapSize / 2 - 1; i >= 0; i--) {  maxHeapify(a, i, heapSize);  }  }  // 找到数组中第k大的元素  int findKthLargest(vector<int>& nums, int k) {  int heapSize = nums.size();  buildMaxHeap(nums, heapSize); // 将nums构建为最大堆  // 移除堆顶元素(即当前最大元素),直到堆中只剩下k个元素  // 每次移除堆顶元素后,重新调整堆  for (int i = nums.size() - 1; i >= nums.size() - k + 1; --i) {  swap(nums[0], nums[i]); // 将堆顶元素与堆尾元素交换  --heapSize; // 堆的大小减一  maxHeapify(nums, 0, heapSize); // 重新调整堆顶元素以满足最大堆的性质  }  // 此时,堆顶元素即为第k大的元素  return nums[0];  }  // 注意:在findKthLargest函数中,循环的条件是i >= nums.size() - k + 1  // 这意味着循环会执行k次,每次移除一个元素,直到堆中只剩下k个元素  // 由于最大堆的性质,堆顶元素始终是最大的,因此最后剩下的堆顶元素就是第k大的元素
};

在这里插入图片描述

class Solution {  
public:  // 静态比较函数,用于比较两个pair的第二个元素(即频率)  // 如果m的频率大于n的频率,则返回true,使得频率高的元素在优先队列中有更高的优先级  static bool cmp(pair<int, int>& m, pair<int, int>& n) {  return m.second > n.second;  }  // 函数用于找出nums中出现频率最高的k个元素  vector<int> topKFrequent(vector<int>& nums, int k) {  // 使用unordered_map记录每个元素的出现次数  unordered_map<int, int> occurrences;  for (auto& v: nums) {  occurrences[v]++;  }  // 定义一个最小堆(但通过自定义比较函数cmp实现最大堆的效果)  // 堆中存储的是pair<int, int>,其中first是元素值,second是元素的出现次数  // 使用decltype(&cmp)作为比较函数的类型,确保类型安全  priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);  // 遍历每个元素及其出现次数  for (auto& [num, count] : occurrences) {  // 如果堆的大小已经达到k,则比较堆顶元素(当前堆中最小的元素,即频率最低的)与当前元素的频率  if (q.size() == k) {  if (q.top().second < count) {  // 如果当前元素的频率大于堆顶元素的频率,则弹出堆顶元素,并将当前元素加入堆中  q.pop();  q.emplace(num, count);  }  // 如果当前元素的频率不大于堆顶元素的频率,则不做任何操作,继续遍历下一个元素  } else {  // 如果堆的大小还未达到k,则直接将当前元素加入堆中  q.emplace(num, count);  }  }  // 构建结果向量,从堆中依次取出元素(即频率最高的k个元素),并将它们逆序排列(因为是从堆中依次弹出的)  // 但由于题目要求只是返回这些元素,而不关心它们的具体顺序,所以这里不需要额外处理顺序问题  vector<int> result;  while (!q.empty()) {  result.emplace_back(q.top().first);  q.pop();  }  // 返回结果向量  return result;  }  
};

在这里插入图片描述

class MedianFinder {  
public:  // 使用最小堆来存储较大的一半元素(确保堆顶为较小的一半中的最大值)  priority_queue<int, vector<int>, greater<int>> queMax;  // 使用最大堆来存储较小的一半元素(确保堆顶为较大的一半中的最小值)  priority_queue<int, vector<int>, less<int>> queMin;  // 构造函数,初始化两个堆  MedianFinder() {}  // 添加一个数到中位数查找器中  void addNum(int num) {  // 如果queMin为空或者新加入的元素小于等于queMin的堆顶元素(即较小一半中的最大值)  if (queMin.empty() || num <= queMin.top()) {  queMin.push(num);  // 如果此时queMin的大小比queMax大2,说明queMin中多出了一个元素,需要将其移动到queMax中  if (queMax.size() + 1 < queMin.size()) {  queMax.push(queMin.top());  queMin.pop();  }  } else {  // 否则,新加入的元素大于queMin的堆顶元素,应该加入到queMax中  queMax.push(num);  // 如果此时queMax的大小比queMin大1,说明queMax中多出了一个元素,需要将其移动到queMin中  if (queMax.size() > queMin.size()) {  queMin.push(queMax.top());  queMax.pop();  }  }  // 通过这种方式,我们保持两个堆的大小平衡,或者queMin比queMax多一个元素(对于奇数个元素的情况)  }  // 查找当前的中位数  double findMedian() {  // 如果queMin中的元素比queMax多,说明元素总数是奇数,中位数就是queMin的堆顶元素  if (queMin.size() > queMax.size()) {  return queMin.top();  }  // 否则,元素总数是偶数,中位数是两个堆顶元素的平均值  return (queMin.top() + queMax.top()) / 2.0;  }  
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/434199.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux网络】详解TCP协议(3)

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux网络 &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解 TCP的流量控制和滑动窗口 的相关内容。 如果看到最后您觉得这篇…

性能测试学习1:性能测试的理论与目的,与功能测试的区别

一.什么是性能&#xff1f; 1&#xff09;性能&#xff1a;就是软件质量属性中的“效率”特性 2&#xff09;效率特性: ①时间特性&#xff1a;表示系统处理用户请求的响应时间【通俗来说&#xff0c;就是使用系统是否流畅】 ②资源特性&#xff1a;表示系统运行过程中&…

锐捷 NBR 1300G路由器 越权CLI命令执行漏洞

漏洞描述 锐捷NBR 1300G路由器 越权CLI命令执行漏洞&#xff0c;guest账户可以越权获取管理员账号密码 漏洞复现 FOFA title"锐捷网络 --NBR路由器--登录界面" 请求包 POST /WEB_VMS/LEVEL15/ HTTP/1.1 Host: Connection: keep-alive Content-Length: 73 Autho…

Python爬虫之requests模块(一)

Python爬虫之requests模块&#xff08;一&#xff09; 学完urllib之后对爬虫应该有一定的了解了&#xff0c;随后就来学习鼎鼎有名的requests模块吧。 一、requests简介。 1、什么是request模块&#xff1f; requests其实就是py原生的一个基于网络请求的模块&#xff0c;模拟…

封装左侧抽屉可拖拽组件【可多个】

一、案例效果 二、案例代码 封装抽屉组件 <template><div class"drag-drawer"><div class"out-box" :style"style"><mtd-tooltip:content"collapse ? 展开面板 : 收起面板"class"tool-tip":placeme…

AI周报(9.22-9.28)

AI应用-Siipet宠物沟通师 Siipet是一款由SiiPet公司推出的创新宠物行为分析相机&#xff0c;旨在通过尖端技术加深宠物与主人之间的情感联系。这款相机利用先进的AI算法&#xff0c;能够自动识别和分析家中宠物的行为&#xff0c;并提供定制化的护理建议。 SiiPet相机的核心功…

GUI-Guider LVGL 添加自定义代码

添加自定义代码时&#xff0c;分为上线两端 1.上部分可有可无 2.下部分为你触发事件时调用的语句 具体集合下方图片 示例参考

Python入门:掌握inspect模块,轻松调试你的代码!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 什么是inspect模块?📝 inspect模块的常用方法📝 1. 获取对象的信息📝 2. 获取函数的参数📝 3. 检查对象类型📝 4. 获取文档字符串📝 5. 获取调用方法的名称📝 实际应用场景⚓️ 相关链接 ⚓️…

[大语言模型-论文精读] Diffusion Model技术-通过时间和空间组合扩散模型生成复杂的3D人物动作

​​​​​​Generation of Complex 3D Human Motion by Temporal and Spatial Composition of Diffusion Models L Mandelli, S Berretti - arXiv preprint arXiv:2409.11920, 2024 通过时间和空间组合扩散模型生成复杂的3D人物动作 摘要 本文提出了一种新的方法&#xff0…

Spring AOP - 注解方式实现

前文已经讨论了基于配置文件方式实现Spring AOP&#xff08;Spring AOP - 配置文件方式实现&#xff09;&#xff0c;本文采用注解的方式实现前文相同的功能。配置步骤如下&#xff1a; 1、项目增加aop依赖&#xff08;pom.xml) <dependency><groupId>org.springfr…

linux 安装 tomcat9、java环境

一、安装 Java环境 1. 下载文件 https://repo.huaweicloud.com/java/jdk/ 或者网盘&#xff1a;通过网盘分享的文件&#xff1a;jdk-8u192-linux-x64.tar.gz 链接: https://pan.baidu.com/s/1V3pQWzgSLJxdrUdmmKueRA 提取码: qspw 2. 查看Linux系统是否有自带的jdk&#xf…

代码随想录_刷题记录_第四次

二叉树 — 理论基础 种类&#xff1a; 满二叉树&#xff08;所有层的节点都是满的&#xff0c;k&#xff1a;深度 节点数量&#xff1a;2^k - 1&#xff09;完全二叉树&#xff08;除了最后一层&#xff0c;其余层全满&#xff0c;并且最后一层从左到右连续&#xff09;二叉搜…

C语言扫盲

文章目录 C版本C语言特征GCCprintf数据类型函数指针内存管理void指针 Struct结构和Union结构typedef预处理器make工具cmake工具Projectintegral of sinc functionemulator embedded systeman event schedule 补充在线Linux终端安装Linux参考 建议还是国外教材学习…人家的PPT比…

【ESP32】Arduino开发 | I2C控制器+I2C主从收发例程

有关I2C控制器的详细介绍放在了IDF开发的文章中&#xff0c;跳转栏目目录可以找到对应的文章。 1. API Arduino启动时就已经实例化了两个I2C设备类&#xff0c;分别对应Wire和Wire1对象。 1.1 初始化 bool begin(int sda, int scl, uint32_t frequency0); // returns true, i…

【2023工业3D异常检测文献】PointCore: 基于局部-全局特征的高效无监督点云异常检测器

PointCore: Efficient Unsupervised Point Cloud Anomaly Detector Using Local-Global Features 1、Background 当前的点云异常检测器可以分为两类&#xff1a; &#xff08;1&#xff09;基于重建的方法&#xff0c;通过自动编码器重建输入点云数据&#xff0c;并通过比较原…

召回09 双塔模型+自监督学习

引入&#xff1a; 自监督学习改进双塔模型&#xff0c;可以提升业务指标。自监督学习是把物品塔学习得更习的更好。 长尾物品的曝光和点击数量太少&#xff0c;训练的样本次数不够。自监督可以更好地学习长尾数据的物品表征。 双塔模型的训练&#xff1a; 线上召回的时候不用纠…

【tbNick专享】虚拟机域控、成员服务器、降级等管理

在 VMware 中完成四台域控服务器、一台成员服务器的创建、降级域控为成员服务器&#xff0c;并创建子域的操作。 1. 创建四台域控和一台成员服务器 1.1 在 VMware 中创建虚拟机 启动 VMware Workstation&#xff1a; 打开 VMware Workstation&#xff0c;点击 “创建新的虚拟…

AIGC学习笔记—minimind详解+训练+推理

前言 这个开源项目是带我的一个导师&#xff0c;推荐我看的&#xff0c;记录一下整个过程&#xff0c;总结一下收获。这个项目的slogan是“大道至简”&#xff0c;确实很简。作者说是这个项目为了帮助初学者快速入门大语言模型&#xff08;LLM&#xff09;&#xff0c;通过从零…

十分钟实现内网连接,配置frp

十分钟实现内网连接&#xff0c;配置frp 一.frp是什么&#xff1f;其实是一款实现外网连接内网的一个工具&#xff0c;个人理解&#xff0c;说白了就像是teamviwer一样&#xff0c;外网能访问内网。 利用处于内网或防火墙后的机器&#xff0c;对外网环境提供 http 或 https 服…

CSS04-Chrome调试工具

Chrome 浏览器提供了一个非常好用的调试工具&#xff0c;可以用来调试我们的 HTML结构和 CSS 样式。