LeetCode 栈与队列篇(12、155、84、239)
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例 2:
输入: "()[]{}"
输出: true
示例 3:
输入: "(]"
输出: false
示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true
solution1 往stack放右括号
class Solution {
public boolean isValid(String s) {
//整一个栈
Stack<Character> stack = new Stack<Character>();
for (char c : s.toCharArray()) {
if (c == '{') stack.push('}');
else if (c == '[') stack.push(']');
else if (c == '(') stack.push(')');
else if (stack.isEmpty() || stack.pop() != c) return false;
}
return stack.isEmpty();
}
}
solution2 往stack放左括号
class Solution {
public boolean isValid(String s) {
if (s.length() == 0) return true;
if ((s.length() & 1) == 1) return false;
Stack<Character> stack = new Stack<>();
Map<Character,Character> map = new HashMap<>();
map.put(')','(');
map.put(']','[');
map.put('}','{');
for (int i = 0 ;i < s.length();i++) {
char c = s.charAt(i);
if (c == '(' || c == '[' || c == '{'){
stack.push(c);
}else{
if (stack.size() == 0 || map.get(c) != stack.pop()) {
return false;
}
}
}
return stack.isEmpty();
}
}
solution3 暴力解法,遍历数组,有对称消掉并继续,没对称结束
class Solution {
// private static final Map<Character,Character> = new HashMap<>()
public boolean isValid(String s) {
if (s.length() == 0) return true; //空
if ((s.length() & 1) == 1) return false; // 奇数、位运算
int length;
do{
length = s.length();
s = s.replace("()","").replace("[]","").replace("{}","");
}while(length!=s.length());
return s.length() == 0;
}
}
solution4 字符串加递归
class Solution {
public boolean isValid(String s) {
if (s.contains("()") || s.contains("[]") || s.contains("{}")) {
return isValid(s.replace("()","").replace("[]","").replace("{}",""));
}else {
return "".equals(s);
}
}
}
155. 最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
示例:
输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。
solution1
//整两个栈
class MinStack {
Stack<Integer> stack;
Stack<Integer> minStack;
public MinStack() {
stack = new Stack<>();
minStack = new Stack<>();
}
public void push(int x) {
stack.push(x);
if (minStack.isEmpty() || x <= minStack.peek()) minStack.push(x);
}
public void pop() {
if (stack.pop().equals(minStack.peek())) minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
solution2
//一个栈
class MinStack {
Stack<Integer> stack;
Integer i;
public MinStack() {
stack = new Stack<>();
}
public void push(int x) {
if (i != null && x <= i) {
stack.push(i);
i = x;
}
if (i == null) i = x;
stack.push(x);
}
public void pop() {
if (stack.pop().equals(i) && !stack.isEmpty()) {
i = stack.pop();
}
if (stack.isEmpty()) i = null;
}
public int top() {
return stack.peek();
}
public int getMin() {
return i;
}
}
class MinStack {
int min = Integer.MAX_VALUE;
Stack<Integer> stack = new Stack<Integer>();
public void push(int x) {
//当前值更小
if(x <= min){
//将之前的最小值保存
stack.push(min);
//更新最小值
min=x;
}
stack.push(x);
}
public void pop() {
//如果弹出的值是最小值,那么将下一个元素更新为最小值
if(stack.pop() == min) {
min=stack.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
solution3
//存差值
class MinStack {
Stack<Long> stack;
long i;
/** initialize your data structure here. */
public MinStack() {
stack = new Stack<>();
}
public void push(int x) {
if (stack.isEmpty()){
i = x;
stack.push(x-i);
}else {
if (x < i) {
stack.push(x-i);
i = x;
}else{
stack.push(x-i);
}
}
}
public void pop() {
Long pop = stack.pop();
//弹出后恢复上一个最小值
if ( pop < 0 ) {
i = i - pop;
}
}
public int top() {
long top = stack.peek();
if (top < 0) {
return (int)i;
}else{
return (int)(top + i);
}
}
public int getMin() {
return (int)i;
}
}
84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
solution1
//暴力解法1
//时间复杂度为(n^3)Java 超时
class Solution {
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) return 0;
int max = heights[0];
for (int i = 0; i < heights.length; i ++) {
for (int j = i; j < heights.length; j ++) {
//每两个之间的最小值为高
int min = heights[j];
for (int k = i;k <= j; k++){
min = Math.min(min,heights[k]);
max = Math.max(max,min*(k-i+1));
}
}
}
return max;
}
}
solution2
//暴力2,以每个柱子为最低点,找到对应的矩形
//时间复杂度为(n^2)
class Solution {
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) return 0;
int max = 0;
for (int i = 0; i < heights.length; i ++) {
//遍历左边,找是否有比本身大的
int left = i;
while (left > 0 && heights[left-1] >= heights[i]){
left --;
}
//遍历右边,找是否有比本身小的
int right = i;
while (right < heights.length - 1 && heights[right+1] >= heights[i]) {
right ++;
}
max = Math.max((right - left + 1)*heights[i],max);
}
return max;
}
}
solution3
// 时间、空间复杂度均为O(n)
// 每个的左右边界为比它小的值,栈从小到大放,可以保证左边界,遇到比它小的为右边界,即可计算矩形面积
class Solution {
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) return 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int max = 0;
//按从小到大插入栈,确保每个插入的值知道它的左边界,遇到比它小的即确定右边界
for (int i = 0; i < heights.length; i ++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
max = Math.max(max,heights[stack.pop()] * (i - stack.peek() - 1));
// 确定了左右边界,右边界为比它小的,左边界为栈里比它小的后一位
}
stack.push(i);
}
//清空栈
while (stack.peek() != -1)
max = Math.max(max, heights[stack.pop()] * (heights.length - stack.peek() - 1));
return max;
}
}
solution4
//用两个数组
class Solution {
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) {
return 0;
}
//整两个数组记录每个数的左右边界,即从左算和右算的最小值
int[] lessFromLeft = new int[heights.length];
int[] lessFromRight = new int[heights.length];
lessFromRight[heights.length - 1] = heights.length;
lessFromLeft [0] = -1;
// 确定左边界
for (int i = 1;i < heights.length; i++){
int p = i-1;
while (p >= 0 && heights[p] >= heights[i]) {
p = lessFromLeft[p];
}
lessFromLeft[i] = p;
}
//确定右边界
for (int i = heights.length - 2;i >= 0;i --){
int p = i + 1;
while(p < heights.length && heights[p] >= heights[i]){
p = lessFromRight[p];
}
lessFromRight[i] = p;
}
int max = 0;
for (int i = 0; i < heights.length; i ++){
max = Math.max(max,(lessFromRight[i]-lessFromLeft[i]-1)*heights[i]);
}
return max;
}
}
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
提示:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length
solution1 暴力法
//时间复杂度为O(nk),Java代码无法通过
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int[] result = new int[nums.length-k+1];
for (int i = 0;i < nums.length-k+1;i ++) {
int max = Integer.MIN_VALUE;
for (int j = i;j < i+k;j++) {
max = Math.max(max,nums[j]);
}
result[i] = max;
}
return result;
}
}
solution2 双端队列
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums.length == 0 || k == 0) return nums; //判空
int[] result = new int[nums.length-k+1]; //返回的结果
Deque<Integer> dq = new ArrayDeque<>(); // 双端队列,从小到大
for (int i = 0; i < nums.length ;i ++){
if (!dq.isEmpty() && dq.peek() < i - k + 1) {
dq.poll();
}
//移除队列内比要插入的小的元素,保证最后一位为最大值
while (!dq.isEmpty() && nums[dq.peekLast()] <= nums[i]) {
dq.pollLast();
}
dq.offer(i);
if (i-k+1 >= 0){ //遍历到第3个开始存值
result[i-k+1] = nums[dq.peek()];
}
}
return result;
}
}
solution3 分块法
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return null;
}
int[] maxfromleft = new int[nums.length];
int[] maxfromright = new int[nums.length];
maxfromleft[0] = nums[0];
maxfromright[nums.length - 1] = nums[nums.length - 1];
//分块 整两个数组记录
for (int i = 1;i < nums.length;i++) {
//从左到右遍历 保证块内从左到右增大
if (i%k == 0) maxfromleft[i] = nums[i];
else maxfromleft[i] = Math.max(maxfromleft[i-1],nums[i]);
//从右到左遍历 保证块内从右到左递增
int j = nums.length - 1 - i;
if (j%k == 0) maxfromright[j] = nums[j];
else maxfromright[j] = Math.max(maxfromright[j+1],nums[j]);
}
int[] output = new int[nums.length - k + 1];
for (int i = 0;i < nums.length - k +1;i ++) {
output[i] = Math.max(maxfromleft[i+k-1],maxfromright[i]);
//取窗口涉及到的左块内最右的值,右块内最左的值进行比较
}
return output;
}
}
//用lamda
public static int[] slidingWindowMax(final int[] in, final int w) {
final int[] max_left = new int[in.length];
final int[] max_right = new int[in.length];
max_left[0] = in[0];
max_right[in.length - 1] = in[in.length - 1];
for (int i = 1; i < in.length; i++) {
max_left[i] = (i % w == 0) ? in[i] : Math.max(max_left[i - 1], in[i]);
final int j = in.length - i - 1;
max_right[j] = (j % w == 0) ? in[j] : Math.max(max_right[j + 1], in[j]);
}
final int[] sliding_max = new int[in.length - w + 1];
for (int i = 0, j = 0; i + w <= in.length; i++) {
sliding_max[j++] = Math.max(max_right[i], max_left[i + w - 1]);
}
LeetCode 栈与队列篇(12、155、84、239)的更多相关文章
- leetcode 栈和队列类型题
1,Valid Parentheses bool isVaild1(string& s) { // 直接列举,不易扩展 stack<char> stk; ; i < s.le ...
- LeetCode刷题 --杂篇 --数组,链表,栈,队列
武汉加油,中国加油.希望疫情早日结束. 由于疫情,二狗寒假在家不能到处乱逛,索性就在家里系统的刷一下算法的内容,一段时间下来倒也有些小小的收获.只是一来家中的小破笔记本写起博客来实在不是很顺手,二来家 ...
- Python笔记_第二篇_面向过程_第二部分_2.路径、栈和队列、内存修改
这一部分分三个主题进行讲解,主要为后面的模块.包.第三方库的概念补充一些相关的内容. 1. 路径(Path): 相对路径和绝对路径. 举例1:我们先导入一个os库(模块)来观察一下路径 import ...
- LeetCode入门指南 之 栈和队列
栈 155. 最小栈 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈. push(x) -- 将元素 x 推入栈中. pop() -- 删除栈顶的元素. top( ...
- 栈和队列数据结构的相互实现[LeetCode]
栈是先进后出,队列是先进后出,这里讨论一下两种数据结构之间的相互实现. 一.用两个栈实现队列 我们用一个栈来实现队列的进队操作(栈A),用另一个栈来实现队列的出队操作(栈B). 1.入队列: 把元素放 ...
- 【LeetCode题解】232_用栈实现队列(Implement-Queue-using-Stacks)
目录 描述 解法一:在一个栈中维持所有元素的出队顺序 思路 入队(push) 出队(pop) 查看队首(peek) 是否为空(empty) Java 实现 Python 实现 解法二:一个栈入,一个栈 ...
- LeetCode 232. 用栈实现队列(Implement Queue using Stacks) 4
232. 用栈实现队列 232. Implement Queue using Stacks 题目描述 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部. pop() -- 从 ...
- leetcode刷题记录——栈和队列
题目 232.用栈实现队列 class MyQueue { private Stack<Integer> in = new Stack<>(); private Stack&l ...
- ACM金牌选手讲解LeetCode算法《栈和队列的高级应用》
大家好,我是编程熊,双非逆袭选手,字节跳动.旷视科技前员工,ACM金牌,保研985,<ACM金牌选手讲解LeetCode算法系列>作者. 上一篇文章讲解了<线性表>中的数组.链 ...
- LeetCode通关:栈和队列六连,匹配问题有绝招
刷题路线参考: https://github.com/chefyuan/algorithm-base https://github.com/youngyangyang04/leetcode-maste ...
随机推荐
- 触发器引起的ADG备库同步错误
数据库alert日志报错ORA-16000,查看对应的trc文件,大致如下报错: *** 2020-10-27 14:09:03.340*** SESSION ID:(3340.75) 2020-10 ...
- P9140 [THUPC 2023 初赛] 背包
prologue 这很难评(调了我 1h,我都想紫砂了. 还是典型得不重构就看不见系列. analysis 如果我们还是一个正常人,那么我们大体上是能看到题目的加粗字,这个格式很明显符合我们的同余最短 ...
- csps 线性dp
合唱队形 正反分别求一遍最长上升子序列,然后枚举中间的最高点,计算出来队列里面的最多人,然后就可以知道需要出列的最少人. 过河 tips:两个互质的数字 p,q,他们所不能拼出来的最小的数字是 \(( ...
- Jackson--FastJson--XStream--代码执行&&反序列化
Jackson--FastJson--XStream--代码执行&&反序列化 Jackson代码执行 (CVE-2020-8840) 影响范围 2.0.0 <= FasterXM ...
- Nodejs环境打包前端项目
Node.js 在Linux下安装和环境搭建/编译项目 安装nodejs:1.下载nodejs源码包 wget https://nodejs.org/dist/v14.16.0/node-v14.16 ...
- Codeforces Round 905 Div 1 (CF1887)
A1. Dances (Easy version) 把 \(a,b\) 序列都从小到大排序,\(a\) 贪心删大的,\(b\) 贪心删小的,二分答案并 \(O(n)\) \(\text{check}\ ...
- 极速指南:在 SpringBoot 中快速集成腾讯云短信功能
前言 今天分享一个SpringBoot集成腾讯云短信的功能,平常除了工作,很多xdm做自己的小项目都可能用到短信,但自己去看文档挺费劲的,我这边就帮你节省时间,直接把步骤给你列出来,照做就行. 实战 ...
- 聊聊 GPU 产品选型那些事
随着人工智能的飞速崛起,随之而来的是算力需求的指数级增加,CPU 已经不足以满足深度学习.大模型计算等场景的海量数据处理需求.GPU 作为一种强大的计算工具,无论是高性能计算.图形渲染还是机器学习领域 ...
- Python 潮流周刊#26:requests3 的现状
你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.本周刊开源,欢迎投稿.另有电报频道作为副刊,补充发布更加丰富的资讯. 品牌赞助 本周刊由"Python猫 ...
- 通过Spring MVC 实现 Restful 风格请求⽀持
通过Spring MVC可以很方便地实现Restful风格的请求支持.Restful风格的请求是一种基于HTTP协议的轻量级的Web服务架构风格,它通过HTTP的GET.POST.PUT.DELETE ...