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\) 次

  • 思路解析

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

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

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

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

class MinStack {
public:
MinStack() { } void push(int val) {
if (val <= getMin()) {
minStack.emplace(val);
}
valStack.emplace(val);
} void pop() {
if (valStack.empty()) {
return;
}
int ret = valStack.top();
valStack.pop();
if (ret == getMin()) {
minStack.pop();
}
} int top() {
return valStack.top();
} int getMin() {
if (minStack.empty()) {
return INT_MAX;
}
return minStack.top();
} private:
stack<int> valStack;
stack<int> minStack;
};

20. 有效的括号

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

有效字符串需满足:

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

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

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

  • 思路解析

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

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

class Solution {
public:
bool isValid(string s) {
stack<char> bracketsStack;
for (auto &iter : s) {
// 遇到左括号就入栈,遇到右括号,判断栈顶是否为其对应的左括号,如果是则出栈
if (typeMap.count(iter) != 0) {
bracketsStack.emplace(iter);
} else {
if (bracketsStack.empty() || iter != typeMap[bracketsStack.top()]) {
return false;
}
bracketsStack.pop();
}
}
if (bracketsStack.empty()) {
return true;
}
return false;
}
private:
unordered_map<char, char> typeMap = {
{'(', ')'},
{'[', ']'},
{'{', '}'}
};
};

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

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

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

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

输入:"abbaca"
输出:"ca" 输入:"abbbaca"
输出:"abaca"
  • 思路解析

string提供了两个操作

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

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

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

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

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

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

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

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

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

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

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

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

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

class CQueue {
public:
CQueue() { } void appendTail(int value) {
stackIn.emplace(value);
} int deleteHead() {
if (stackOut.empty()) {
while (!stackIn.empty()) {
stackOut.emplace(stackIn.top());
stackIn.pop();
}
}
if (stackOut.empty()) {
return -1;
}
auto ret = stackOut.top();
stackOut.pop();
return ret;
} private:
stack<int> stackOut; // 输出栈,元素按照输入顺序的栈
stack<int> stackIn; // 输入元素存放栈,与输入顺序相反的栈
};

239. 滑动窗口最大值

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

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

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

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

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

完整的实现代码如下:

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> dQ;
for (size_t i = 0; i < k; i++) {
// 当前队列中仅保留比当前元素大的元素的位置,队列中下标对应的元素由大到小
while (!dQ.empty() && nums[i] >= nums[dQ.back()]) {
dQ.pop_back();
}
dQ.emplace_back(i);
}
vector<int> resVec = {nums[dQ.front()]};
for (size_t i = k; i < nums.size(); i++) {
// 当前队列中仅保留比当前元素大的元素的位置
while (!dQ.empty() && nums[i] >= nums[dQ.back()]) {
dQ.pop_back();
}
dQ.emplace_back(i);
if (dQ.front() <= i - k) {
dQ.pop_front();
}
resVec.emplace_back(nums[dQ.front()]);
}
return resVec;
}

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

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. 外形最漂亮的人形机器人——通用机器人Apollo,设计为可以在任何任务和环境中与人类进行协作

    视频地址: https://www.bilibili.com/video/BV11F4m1M7ph/

  2. ubuntu22.04系统环境下使用vs code安装pylint检查python的代码错误

    紧跟前文: ubuntu18.04系统环境下使用vs code安装pylint检查python的代码错误 pylint官网: https://pylint.pycqa.org/ =========== ...

  3. Quartz.NET 的使用

    先貼使用代碼: 1 using Quartz; 2 using Quartz.Impl; 3 using Quartz.Logging; 4 using System; 5 using System. ...

  4. Unity编辑器批量设置图片格式

    在游戏开发中,经常需要批量设置图片的格式为Sprite类型,手动设置太麻烦,下面的编辑器脚本实现选中文件夹右键/Texture/SetAllImagesToSpriteType实现批量设置图片格式,具 ...

  5. Pintia 天梯地图 dijkstra进阶

    7-14 天梯地图 - SMU 2024 spring 天梯赛3(补题) (pintia.cn) dijkstra进阶做法,包含路径记录,以及按权重统计路径条件等; 不过最开始我一直将优先队列开的最大 ...

  6. 嵌入式工程师到底要不要学习ARM汇编指令?arm学习文章汇总

    嵌入式工程师到底要不要学习ARM汇编指令? 网上搜索这个问题,答案很多,大部分的建议是不要学汇编,只要学C语言. 而一口君作为一个十几年经验的驱动工程师,个人认为,汇编语言还是需要掌握的,想要搞精.搞 ...

  7. Microsoft Ignite China, Watch Party - Why adopt Windows 11 today 升级了啥?

    Microsoft Ignite 2021 大会采用线上直播形式,围绕云技术.数据智能.未来工作方式.全民创新及数据安全等技术议题,结合全球及本地最新产品发布.科技趋势与成功案例,将带您体验独一无二的 ...

  8. psutil 检测exe是否已经运行

    安装依赖 pip install psutil 代码 import psutil def check_if_process_running(process_name): ''' Check if th ...

  9. .net 环境使用 RabbitMQ ,由浅入深 【一】

    最近因为先开发的项目需要用到消息队列,因此捣鼓了一下市面上开源的消息队列. 原本听闻Rocketmq ,一开始用的是 RocketMQ,各种集群搭建完毕,消息发送什么的测试后,,但是结果因为 Rock ...

  10. Authentication vs. Authorization

    Authentication vs. Authorization So, what is the difference between authentication and authorization ...