1 有效的括号
不难,但是要考虑多种情况
技巧:入栈的时候,( 就入 ),[ 就入 ]。
如果遇到右括号,则判断stack是否为空,考虑())的情况
再考虑当前字符c != stack.peek()的情况,也就是(( ] )的情况。
上面这两种情况直接返回fals就行。
第三种情况就是正常匹配,当前字符是)且栈顶是(,那么直接stack.pop()就行。
最后结束for循环,返回stack.isEmpty();
如果不为空,说明左括号有剩余,[ [ [ ]的情况就是,直接返回false;栈空则说明是有效的括号,返回true;
java
class Solution {
public boolean isValid(String s) {
Deque<Character> stack = new LinkedList<>();
int len = s.length();
for (int i = 0; i < len; i++) {
if (s.charAt(i) == '(') {
stack.push(')');
} else if (s.charAt(i) == '[') {
stack.push(']');
} else if (s.charAt(i) == '{') {
stack.push('}');
} else if (stack.size() == 0 || s.charAt(i) != stack.peek()) {
return false;
} else {
stack.pop();
}
}
return stack.isEmpty();
}
}
2 最小栈
核心思路:辅助栈法(最优解)
主栈:存储所有入栈的元素,实现普通栈的基本操作;
辅助栈:同步存储「当前主栈中的最小值」,保证辅助栈的栈顶始终是主栈当前的最小值。
push:主栈入栈元素,辅助栈入栈「当前元素与辅助栈顶的较小值」;
pop:主栈和辅助栈同时出栈(保证两者长度一致);
getMin:直接返回辅助栈的栈顶元素。
java
class MinStack {
private Deque<Integer> mainStack;
private Deque<Integer> minStack;
public MinStack() {
mainStack = new LinkedList<>();
minStack = new LinkedList<>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int val) {
mainStack.push(val);
int curMin = Math.min(val, minStack.peek());
minStack.push(curMin);
}
public void pop() {
mainStack.pop();
minStack.pop();
}
public int top() {
return mainStack.peek();
}
public int getMin() {
return minStack.peek();
}
}
3 字符串解码
数字栈:存储待处理的重复次数 k(处理多位数,如 12[abc] 中的 12);
字符串栈:存储待拼接的前缀字符串(处理嵌套时的外层字符串,如 3[a2[b]] 中 2[b] 外层的 a);
遍历逻辑:
遇到数字:累积计算多位数(如 12 = 1*10 + 2);
遇到 [:将当前累积的数字压入数字栈,当前拼接的字符串压入字符串栈,然后重置数字和字符串;
遇到 ]:弹出数字栈的重复次数 k,弹出字符串栈的前缀字符串,将当前字符串重复 k 次后拼接到前缀后;
遇到字母:直接拼接到当前字符串。
java
import java.util.Deque;
import java.util.LinkedList;
class Solution {
public String decodeString(String s) {
// 数字栈:存储待执行的重复次数(处理嵌套结构时的"重复指令")
Deque<Integer> numStack = new LinkedList<>();
// 字符串栈:存储括号外层的前缀字符串(处理嵌套时的"外层存档")
Deque<String> strStack = new LinkedList<>();
// 当前正在拼接的临时字符串(括号内待重复的内容)
StringBuilder curStr = new StringBuilder();
// 当前累积的数字(处理多位数,如"12[a]"中的12需要逐步计算)
int curNum = 0;
// 将字符串转为字符数组,方便逐个遍历
char[] sArr = s.toCharArray();
// 遍历每个字符,逐字符处理解码逻辑
for (char c : sArr) {
// 情况1:当前字符是数字 → 累积计算多位数
if (Character.isDigit(c)) {
// 例如:curNum=1,遇到'2' → 1*10 + 2 = 12
curNum = curNum * 10 + (c - '0');
}
// 情况2:当前字符是左括号'[' → 存档当前状态,准备处理括号内内容
else if (c == '[') {
// 1. 把当前累积的重复次数压入数字栈(存档)
numStack.push(curNum);
// 2. 把当前拼接的字符串压入字符串栈(存档外层前缀)
strStack.push(curStr.toString());
// 3. 重置临时数字,准备处理括号内的新数字
curNum = 0;
// 4. 重置临时字符串,准备拼接括号内的内容
curStr = new StringBuilder();
}
// 情况3:当前字符是右括号']' → 拼接重复后的字符串
else if (c == ']') {
// 1. 弹出数字栈顶的重复次数(本次要重复的次数)
int loop = numStack.pop();
// 2. 弹出字符串栈顶的前缀(括号外的内容)
String prefix = strStack.pop();
// 3. 新建临时字符串,先拼接外层前缀
StringBuilder temp = new StringBuilder(prefix);
// 4. 把当前括号内的字符串重复指定次数,拼接到前缀后
for (int i = 0; i < loop; i++) {
temp.append(curStr.toString());
}
// 5. 更新临时字符串为拼接后的结果,继续处理外层逻辑
curStr = temp;
}
// 情况4:当前字符是字母 → 直接拼接到临时字符串
else {
curStr.append(c);
}
}
// 遍历结束,返回最终拼接完成的解码字符串
return curStr.toString();
}
}
4 每日温度
单调递减栈
先把下标0push入栈
然后从1开始,如果温度比栈顶下标的温度低,那就入栈。
如果下标i对应的温度比栈顶下标的温度高,那么就进入while循环,!st.isEmpty()&&t[i] >t[st.peek()]
然后给res[st.peek()]赋值为i-st.peek()
st.pop()
最后退出while循环,把i push进去
java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
Deque<Integer> st = new LinkedList<>();
st.push(0);
int len = temperatures.length;
int[] res = new int[len];
for (int i = 1; i < len; i++) {
if (temperatures[i] <= temperatures[st.peek()]) {
st.push(i);
} else {
while (!st.isEmpty() && temperatures[i] > temperatures[st.peek()]) {
res[st.peek()] = i - st.peek();
st.pop();
}
st.push(i);
}
}
return res;
}
}
5 柱状图中最大的矩形
单调递增栈
遇到h[i] < h[st.peek()]的就while()出栈
height = h[st.pop()]
width = i - st.peek() - 1;
更新area
加左右哨兵,同意边界处理,让第一个能入栈,最后一个能弹出。
java
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if (len == 1) return heights[0];
int[] newHeights = new int[len + 2];
for (int i = 0; i < len; i++) {
newHeights[i + 1] = heights[i];
}
newHeights[0] = 0;
Deque<Integer> st = new LinkedList<>();
int res = 0;
for (int i = 0; i < newHeights.length; i++) {
while (!st.isEmpty() && newHeights[i] < newHeights[st.peek()]) {
int curIndex = st.pop();
int curHeight = newHeights[curIndex];
int width = i - st.peek() - 1;
res = Math.max(res, width * curHeight);
}
st.push(i);
}
return res;
}
}