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. Java 文件 I/O流详解

    文件 文件操作是Java开发中一个重要的组成部分,它允许开发者对文件进行读取,写入,创建,删除和修改等操作,文件操作的主要通过java.io包中的类来实现的,其中的File类更是文件操作的核心类 Fi ...

  2. 人形机器人(具身智能,Embodied Intelligence)—— 抓取动作(上半身动作规划)的各大公司技术路线

    视频地址: https://www.youtube.com/watch?v=UZBSXzNKB1Q

  3. 国产操作系统——银河麒麟V10 SP1使用小结

    前几天看新闻国产操作系统银河麒麟有了新的更新于是上手搞了一个. ========================================================= 该系统自带驱动,其中 ...

  4. 社区6月月报 | Apache DolphinScheduler重要修复和优化记录

    各位热爱Apache DolphinScheduler的小伙伴们,社区6月月报更新啦!这里将记录Apache DolphinScheduler社区每月的重要更新,欢迎关注. 月度Merge Stars ...

  5. Apache DolphinScheduler 3.0.6 发布,或将是最后一个 3.0.X 版本

    Apache DolphinScheduler 于近日发布了 3.0.6 版本,主要针对 3.0.5 重要 bug 进行修复.如果之后没有发现重大问题,3.0.6 将会是 3.0.x 最后一个版本. ...

  6. Java核心技术之Date相关

    import java.time.DayOfWeek; import java.time.LocalDate; import java.util.Scanner; /** * @author Suns ...

  7. 解决 Docker CE 在无根模式(rootless)下无法通过 IPv6 拉取映像的问题

    折腾一天快把我逼疯了 本来 Docker 对 IPv6 的支持就不好,再来个 rootless,雪上加霜 首先,我们要区分 Docker Engine 和 里面的 Image. 拉取映像是 Docke ...

  8. Linux与windows共享文件的神器:samba

    一.什么是samba? 搭建Samba服务器是为了实现Linux共享目录之后,在Windows可以直接访问该共享目录. 现在介绍如何在ubuntu 16.04系统中搭建Samba服务. 二 .samb ...

  9. B2B进销存ERP后台管理系统的逻辑架构与设计,AxureRP原型产品经理实战案例

    模块分析: 进销存系统是一种用于企业管理库存.销售和采购活动的信息系统.它的主要作用包括但不限于以下几个方面: 1.库存管理 实时库存跟踪:准确记录每种商品的库存数量,确保数据的实时性和准确性. 库存 ...

  10. RedisTemplate常用方法

    RedisTemplate常用方法 一.Redis常用的数据类型: String Hash List Set zSet Sorted set 二.RedisTemplate 常用 API 1. Str ...