155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

提示:

  • \(-2^{31}\) <= val <= \(2^{31}\) - 1

  • pop、top 和 getMin 操作总是在 非空栈 上调用

  • push, pop, top, and getMin最多被调用 \(3 * 10^4\) 次

  • 思路解析

因为会不断的入栈和出栈,那就要保证,不论入栈还是出栈,我时刻知道,到栈中当前位置的最小值是谁。

  1. ["MinStack","push","push","push","getMin","pop","top","getMin"]
  2. [[],[-2],[0],[-3],[],[],[],[]]

对于上述输入,-2入栈时,最小值是-2,0入栈是,最小值是-2,-3入栈是最小值是-3

也就是我需要两个栈,一个栈用于存储元素,完成元素的push和pop操作;一个栈用于存储当前最小值,如果最小值更新就存入最小栈。

  1. class MinStack {
  2. public:
  3. MinStack() {
  4. }
  5. void push(int val) {
  6. if (val <= getMin()) {
  7. minStack.emplace(val);
  8. }
  9. valStack.emplace(val);
  10. }
  11. void pop() {
  12. if (valStack.empty()) {
  13. return;
  14. }
  15. int ret = valStack.top();
  16. valStack.pop();
  17. if (ret == getMin()) {
  18. minStack.pop();
  19. }
  20. }
  21. int top() {
  22. return valStack.top();
  23. }
  24. int getMin() {
  25. if (minStack.empty()) {
  26. return INT_MAX;
  27. }
  28. return minStack.top();
  29. }
  30. private:
  31. stack<int> valStack;
  32. stack<int> minStack;
  33. };

20. 有效的括号

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。

  • 左括号必须以正确的顺序闭合。

  • 每个右括号都有一个对应的相同类型的左括号。

  • 思路解析

将匹配项做一个map单独存储,这样子有更好的扩展性。

遇到左括号就入栈,遇到右括号,判断是否与栈顶元素配对,配上就出栈,否则就返回false。

  1. class Solution {
  2. public:
  3. bool isValid(string s) {
  4. stack<char> bracketsStack;
  5. for (auto &iter : s) {
  6. // 遇到左括号就入栈,遇到右括号,判断栈顶是否为其对应的左括号,如果是则出栈
  7. if (typeMap.count(iter) != 0) {
  8. bracketsStack.emplace(iter);
  9. } else {
  10. if (bracketsStack.empty() || iter != typeMap[bracketsStack.top()]) {
  11. return false;
  12. }
  13. bracketsStack.pop();
  14. }
  15. }
  16. if (bracketsStack.empty()) {
  17. return true;
  18. }
  19. return false;
  20. }
  21. private:
  22. unordered_map<char, char> typeMap = {
  23. {'(', ')'},
  24. {'[', ']'},
  25. {'{', '}'}
  26. };
  27. };

1047. 删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

  1. 输入:"abbaca"
  2. 输出:"ca"
  3. 输入:"abbbaca"
  4. 输出:"abaca"
  • 思路解析

string提供了两个操作

  • front:访问第一个字符
  • back:查询最后一个字符
  • pop_back:弹出尾巴字符,实现:length - 1即可
  • push_back:插入元素
  1. string removeDuplicates(string s) {
  2. string res;
  3. for (auto &iter : s) {
  4. if (!res.empty() && iter == res.back()) {
  5. res.pop_back();
  6. } else {
  7. res.push_back(iter);
  8. }
  9. }
  10. return res;
  11. }

1209. 删除字符串中的所有相邻重复项 II

给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。

你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。

在执行完所有删除操作后,返回最终得到的字符串。

  1. 输入:s = "deeedbbcccbdaa", k = 3
  2. 输出:"aa"
  3. 解释:
  4. 先删除 "eee" "ccc",得到 "ddbbbdaa"
  5. 再删除 "bbb",得到 "dddaa"
  6. 最后删除 "ddd",得到 "aa"
  • 思路解析

遍历到某个字符的时候,判断当前字符与栈顶字符是否相同

  • 如果不同,则直接入栈并开始计数
  • 如果相同,则判断当前栈顶元素累积了多少个该元素,如果累积的个数小于k-1,则继续累积,如果累积到了k-1个,当前又相同了,那么栈顶元素就可以弹出了。
  1. string removeDuplicates(string s, int k) {
  2. stack<std::pair<char, int>> pairStack; // 每个元素存储当前的元素及有几个连续的值
  3. for (size_t i = 0; i < s.length(); i++) {
  4. if (!pairStack.empty() && pairStack.top().first == s[i]) {
  5. // 此时,看一下栈中是否已经有k-1个s[i]相同的元素,如果有,则pop出这k-1个,如果没有,则push进去
  6. if (pairStack.top().second == k - 1) {
  7. pairStack.pop();
  8. } else {
  9. pairStack.top().second++;
  10. }
  11. } else {
  12. pairStack.emplace(std::pair<char, int>(s[i], 1));
  13. }
  14. }
  15. string res;
  16. while(!pairStack.empty()) {
  17. while (pairStack.top().second-- > 0) {
  18. res += pairStack.top().first;
  19. }
  20. pairStack.pop();
  21. }
  22. reverse(res.begin(), res.end());
  23. return res;
  24. }

删除字符串中出现次数 >= 2 次的相邻字符

第二次出现的时候,说明出现次数大于2了,这时候就可以删除了,同时跳过s中后续与当前字符相同的元素即可。

  1. string removeDuplicates(string s, int k) {
  2. string res; // 每个元素存储当前的元素及有几个连续的值
  3. for (size_t i = 0; i < s.length(); ) {
  4. if (!res.empty() && res.back() == s[i]) {
  5. // 此时,说明已经出现过的字符第二次出现了
  6. char currChar = s[i];
  7. while(s[i] == currChar) {
  8. // 跳过s中其他相同的字符
  9. i++;
  10. }
  11. res.pop_back();
  12. } else {
  13. res.push_back(s[i]);
  14. i++;
  15. }
  16. }
  17. return res;
  18. }

剑指 Offer 09. 用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

  1. class CQueue {
  2. public:
  3. CQueue() {
  4. }
  5. void appendTail(int value) {
  6. stackIn.emplace(value);
  7. }
  8. int deleteHead() {
  9. if (stackOut.empty()) {
  10. while (!stackIn.empty()) {
  11. stackOut.emplace(stackIn.top());
  12. stackIn.pop();
  13. }
  14. }
  15. if (stackOut.empty()) {
  16. return -1;
  17. }
  18. auto ret = stackOut.top();
  19. stackOut.pop();
  20. return ret;
  21. }
  22. private:
  23. stack<int> stackOut; // 输出栈,元素按照输入顺序的栈
  24. stack<int> stackIn; // 输入元素存放栈,与输入顺序相反的栈
  25. };

239. 滑动窗口最大值

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。

  1. 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
  2. 输出:[3,3,5,5,6,7]
  3. 解释:
  4. 滑动窗口的位置 最大值
  5. --------------- -----
  6. [1 3 -1] -3 5 3 6 7 3
  7. 1 [3 -1 -3] 5 3 6 7 3
  8. 1 3 [-1 -3 5] 3 6 7 5
  9. 1 3 -1 [-3 5 3] 6 7 5
  10. 1 3 -1 -3 [5 3 6] 7 6
  11. 1 3 -1 -3 5 [3 6 7] 7
  • 思路解析

假设窗口为[left, right],那么只要nums[i]比nums[j]小,则nums[i]就不纳入考虑范围。所以,当right进入窗口的时候,前面比nums[right]小的元素统统可以移除考虑范围了;这样子,留下的元素是从大到小有序的。

因为我们要移除比当前元素小的元素,也要获取最大的元素作为当前窗口最大值,因此,可以使用双端队列来实现。

  1. // 移除比当前元素小的所有元素,只留下比当前元素大的元素
  2. while (!dQ.empty() && nums[i] >= nums[dQ.back()]) {
  3. dQ.pop_back();
  4. }
  5. // 获取当前窗口最大值,放入结果中
  6. resVec.emplace_back(nums[dQ.front()]);
  7. // 如果最大值应该要移除了,则移除
  8. if (dQ.front() + k <= i) {
  9. dQ.pop_front();
  10. }

完整的实现代码如下:

  1. vector<int> maxSlidingWindow(vector<int>& nums, int k) {
  2. deque<int> dQ;
  3. for (size_t i = 0; i < k; i++) {
  4. // 当前队列中仅保留比当前元素大的元素的位置,队列中下标对应的元素由大到小
  5. while (!dQ.empty() && nums[i] >= nums[dQ.back()]) {
  6. dQ.pop_back();
  7. }
  8. dQ.emplace_back(i);
  9. }
  10. vector<int> resVec = {nums[dQ.front()]};
  11. for (size_t i = k; i < nums.size(); i++) {
  12. // 当前队列中仅保留比当前元素大的元素的位置
  13. while (!dQ.empty() && nums[i] >= nums[dQ.back()]) {
  14. dQ.pop_back();
  15. }
  16. dQ.emplace_back(i);
  17. if (dQ.front() <= i - k) {
  18. dQ.pop_front();
  19. }
  20. resVec.emplace_back(nums[dQ.front()]);
  21. }
  22. return resVec;
  23. }

需要完整版练习笔记,可关注公众号后台私信~~

Leetcode Practice --- 栈和队列的更多相关文章

  1. leetcode - 使用栈实现队列的特性

    使用栈实现队列的特性 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部. pop() -- 从队列首部移除元素. peek() -- 返回队列首部的元素. empty() - ...

  2. 栈和队列数据结构的相互实现[LeetCode]

    栈是先进后出,队列是先进后出,这里讨论一下两种数据结构之间的相互实现. 一.用两个栈实现队列 我们用一个栈来实现队列的进队操作(栈A),用另一个栈来实现队列的出队操作(栈B). 1.入队列: 把元素放 ...

  3. 【LeetCode题解】232_用栈实现队列(Implement-Queue-using-Stacks)

    目录 描述 解法一:在一个栈中维持所有元素的出队顺序 思路 入队(push) 出队(pop) 查看队首(peek) 是否为空(empty) Java 实现 Python 实现 解法二:一个栈入,一个栈 ...

  4. LeetCode 232. 用栈实现队列(Implement Queue using Stacks) 4

    232. 用栈实现队列 232. Implement Queue using Stacks 题目描述 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部. pop() -- 从 ...

  5. LeetCode刷题 --杂篇 --数组,链表,栈,队列

    武汉加油,中国加油.希望疫情早日结束. 由于疫情,二狗寒假在家不能到处乱逛,索性就在家里系统的刷一下算法的内容,一段时间下来倒也有些小小的收获.只是一来家中的小破笔记本写起博客来实在不是很顺手,二来家 ...

  6. ACM金牌选手讲解LeetCode算法《栈和队列的高级应用》

    大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM金牌,保研985,<ACM金牌选手讲解LeetCode算法系列>作者. 上一篇文章讲解了<线性表>中的数组.链 ...

  7. 代码随想录算法训练营day10 | leetcode 232.用栈实现队列 225. 用队列实现栈

    基础知识 使用ArrayDeque 实现栈和队列 stack push pop peek isEmpty() size() queue offer poll peek isEmpty() size() ...

  8. 【Leetcode】 剑指offer:栈与队列 --Day01

    写在前面 2023届秋招形势严峻,作为2024届本科生倍感压力.时间紧迫,需要加快脚步. 计划之一是在未来的36天时间里通关Leetcode的剑指offer系列算法题.这一系列的学习周期为31天,也就 ...

  9. 【leetcode 简单】 第六十六题 用栈实现队列

    使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部. pop() -- 从队列首部移除元素. peek() -- 返回队列首部的元素. empty() -- 返回队列是否为空. ...

  10. LeetCode 225:用队列实现栈 Implement Stack using Queues

    题目: 使用队列实现栈的下列操作: push(x) -- 元素 x 入栈 pop() -- 移除栈顶元素 top() -- 获取栈顶元素 empty() -- 返回栈是否为空 Implement th ...

随机推荐

  1. 【Ubuntu】下载安装 12.04.5版本 桌面端

    下载 Download 我擦早上起来才发现自己装的是远古版本了,唉算了,反正也没见过,就当是学个东西把 [下载地址:点我访问] https://releases.ubuntu.com/?_ga=2.2 ...

  2. NVIDIA的人形机器人的基础模型Project GR00T已在实体机器人上进行展示

    原文地址: https://blogs.nvidia.com/blog/isaac-generative-ai-manufacturing-logistics/ 项目GR00T为人型机器人开发谢幕 在 ...

  3. 机器人的运动控制是否可以引入生物学信息,生物学信息是否可以辅助机器人的智能控制算法的训练:《Robotic prosthetic ankles improve 'natural' movement, stability》

    相关内容: Robotic prosthetic ankles improve 'natural' movement, stability 看了上面的论文的介绍(内容没看到,不是open access ...

  4. Apache DolphinScheduler:深入了解大数据调度工具

    一.海豚调度介绍 Apache DolphinScheduler 是一个分布式易扩展的可视化DAG工作流任务调度开源系统.适用于企业级场景,提供了一个可视化操作任务.工作流和全生命周期数据处理过程的解 ...

  5. double四舍五入保留两位小数的方法

    1,DecimalFormat DecimalFormat decimalFormat = new DecimalFormat(".00"); 意思就是规定保留几位小数 使用时 d ...

  6. 100ASK_IMX6ULL arm板子如何显示图片、汉字、划线、背景色

    最近在研究基于imx6ull开发板,想让开发板支持显示图片.字符串.背景色的功能. 操作的主要步骤如下: 移植设备树和驱动 移植libjpeg库 编写测试程序 一.移植设备树和驱动 开发板原厂SDK已 ...

  7. Oracle导出数据库与还原

    导出部分 1.获取到Oracle directory目录与实际电脑目录的映射 2.CMD导出Oracle数据库 DMP文件 //expdp 用户/密码@数据库监听地址 schemas=表空间名称 du ...

  8. C#使用泛型方法将Datatable转换成List对象集合

    在项目中遇到需要将Datatable转换成对象的需求,通过dr[0]取下标这种获取,如果数据的顺序发生了改变则需要改变全部,工作量大 foreach (DataRow dr in dt.Rows) { ...

  9. 阿里云图床(PicGo+阿里云OSS)搭建

    阿里云图床搭建方法: 1.登录阿里云,搜索对象存储oss,新用户免费使用3个月20G,到期后,一年也就9元左右,还是很划算的. 2.在左侧列表里,点击Bucket列表,创建Bucket 3.Bucke ...

  10. FFmpeg开发笔记(四十九)助您在毕业设计中脱颖而出的几个流行APP

    ​对各高校即将毕业的学子来说,毕业设计算是在大学里的最后一个大作业.特别是软件.计算机.电子等相关专业,毕业设计非常讲究实操,往往要求实现一个实用的.可用的.易用的软件系统或手机APP. 不管是软件还 ...