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)的更多相关文章

  1. leetcode 栈和队列类型题

    1,Valid Parentheses bool isVaild1(string& s) { // 直接列举,不易扩展 stack<char> stk; ; i < s.le ...

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

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

  3. Python笔记_第二篇_面向过程_第二部分_2.路径、栈和队列、内存修改

    这一部分分三个主题进行讲解,主要为后面的模块.包.第三方库的概念补充一些相关的内容. 1. 路径(Path): 相对路径和绝对路径. 举例1:我们先导入一个os库(模块)来观察一下路径 import ...

  4. LeetCode入门指南 之 栈和队列

    栈 155. 最小栈 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈. push(x) -- 将元素 x 推入栈中. pop() -- 删除栈顶的元素. top( ...

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

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

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

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

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

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

  8. leetcode刷题记录——栈和队列

    题目 232.用栈实现队列 class MyQueue { private Stack<Integer> in = new Stack<>(); private Stack&l ...

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

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

  10. LeetCode通关:栈和队列六连,匹配问题有绝招

    刷题路线参考: https://github.com/chefyuan/algorithm-base https://github.com/youngyangyang04/leetcode-maste ...

随机推荐

  1. Go 复合类型之切片类型介绍

    Go 复合类型之切片类型 目录 Go 复合类型之切片类型 一.引入 二.切片(Slice)概述 2.1 基本介绍 2.2 特点 2.3 切片与数组的区别 三. 切片声明与初始化 3.1 方式一:使用切 ...

  2. 可视化-vscode使用Plotly,绘制直方图

    Plotly 是一款用来做数据分析和可视化的在线平台,功能非常强大,可以在线绘制很多图形比如条形图.散点图.饼图.直方图等等. 概述: plotly在python中绘图使用分三种:1.plotly.g ...

  3. 03-11gR2单机通过RMAN恢复到RAC(未验证)

    1.在单机上做一个完全备份,并将备份集拷贝到RAC的第一个节点上. 2.强行启动到nomount 3.恢复spfile 4.创建pfile,修改pfile,重建spfile #####修改contro ...

  4. C语言存储类别

    对于C语言中的变量,存储类别可分为4种:auto(自动存储).static(静态存储).register(寄存器存储).extern(外部存储). auto自动存储 函数中的局部变量,如果不专门声明为 ...

  5. chatgpt镜像站汇总 - 聚合GPT【即时更新】

    自荐下由我开发的聚合GPT网站,这边的GPT镜像站均为免费.无登录.无次数限制的!会及时剔除失效.添加可用地址[欢迎STAR.PR] 地址:https://ele-cat.gitee.io/comp- ...

  6. CSP2023 模拟赛总结合集

    9.9 ZZFLS 感觉 ucup 剩下的题完全不可做了啊!先对比赛时间来写总结对队友道歉(鞠躬.jpg 开题策略很失败.开场 30min 得的分数是一整场考试的分数. 开题,发现 T1 是水题,30 ...

  7. 21.8 Python 使用BeautifulSoup库

    BeautifulSoup库用于从HTML或XML文件中提取数据.它可以自动将复杂的HTML文档转换为树形结构,并提供简单的方法来搜索文档中的节点,使得我们可以轻松地遍历和修改HTML文档的内容.广泛 ...

  8. codeforces #864 div2 B

    GCD Partition 这道题首先要解决一个问题,要把区间分成几块,可以证明分成两块是更优 首先我们假设把区间分成了m(>= 2)块 b1, b2, b3, ...,bm,则答案是gcd(b ...

  9. P7073 [CSP-J2020] 表达式

    Problem 考察算法:后缀表达式建树,优化. 题目简述 读入一个后缀表达式,由 \(\&,\mid,!\) 三种运算和操作数构成. 有 \(q\) 次询问,每次输入一个下标 \(i\) , ...

  10. 极致性能优化:前端SSR渲染利器Qwik.js

    引言 前端性能已成为网站和应用成功的关键要素之一.用户期望快速加载的页面和流畅的交互,而前端框架的选择对于实现这些目标至关重要.然而,传统的前端框架在某些情况下可能面临性能挑战且存在技术壁垒. 在这个 ...