有效的括號
解法:壓棧出棧
public class Solution {
public boolean isValid(String s) {
Deque<Character> deque = new LinkedList<>();
Map<Character, Character> map = new HashMap<>();
map.put(')', '(');
map.put(']', '[');
map.put('}', '{');
for (char c : s.toCharArray()) {
if (deque.isEmpty() || deque.peekFirst() != map.get(c)) {
deque.offerFirst(c);
} else {
deque.pollFirst();
}
}
return deque.isEmpty();
}
public static void main(String[] args) {
boolean valid = new Solution().isValid("()[]][");
System.out.println(valid);
}
}
最小棧
思路:
- 運用兩個棧,維護一個值棧和一個最小值棧
- 入棧時判斷值是否大於最小值棧棧頂,如果大於等於就複製一個棧頂元素到棧頂
- 如果入棧元素小於最小值棧頂,加入最小值棧
class MinStack {
Deque<Integer> deque;
Deque<Integer> minDeque;
/**
* initialize your data structure here.
*/
public MinStack() {
//值棧
deque = new LinkedList<>();
//最小值棧
minDeque = new LinkedList<>();
}
public void push(int x) {
//入值棧
deque.offerFirst(x);
//如果x小於最小值棧頂,就如最小值棧
if (minDeque.isEmpty() || minDeque.peekFirst() >= x) {
minDeque.offerFirst(x);
} else {
//如果最小值棧數小於x,就拷貝一份最小值在棧頂
minDeque.offerFirst(minDeque.peekFirst());
}
}
public void pop() {
deque.pollFirst();
minDeque.pollFirst();
}
public int top() {
return deque.peekFirst();
}
public int getMin() {
return minDeque.peekFirst();
}
}
用棧實現隊列
class MyQueue {
Stack<Integer> in;
Stack<Integer> out;
/**
* Initialize your data structure here.
*/
public MyQueue() {
in = new Stack<>();
out = new Stack<>();
}
/**
* Push element x to the back of queue.
*/
public void push(int x) {
in.push(x);
}
/**
* Removes the element from in front of queue and returns that element.
*/
public int pop() {
if (out.isEmpty()) {
while (!in.isEmpty()) {
out.push(in.pop());
}
}
return out.pop();
}
/**
* Get the front element.
*/
public int peek() {
if (out.isEmpty()) {
while (!in.isEmpty()) {
out.push(in.pop());
}
}
return out.peek();
}
/**
* Returns whether the queue is empty.
*/
public boolean empty() {
return in.isEmpty() && out.isEmpty();
}
}
用隊列實現棧
思路:維護兩個隊列,保證總有一個隊列是空的
- push操作,加入到非空的隊列中
- pop操作,將隊列中size-1的數加入到空的隊列,留下最後一個pop出去
- top操作,將隊列中size-1的數加入到空的隊列,留下最後一個記錄爲top,再加入到新隊列,返回top
- empty操作,兩個隊列同時滿足爲空
class MyStack {
LinkedList<Integer> queue1;
LinkedList<Integer> queue2;
/**
* Initialize your data structure here.
*/
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/**
* Push element x onto stack.
*/
public void push(int x) {
if (queue1.isEmpty()) {
queue2.offer(x);
} else {
queue1.offer(x);
}
}
/**
* Removes the element on top of the stack and returns that element.
*/
public int pop() {
if (queue1.isEmpty()) {
while (queue2.size() > 1) {
queue1.offer(queue2.poll());
}
return queue2.poll();
} else {
while (queue1.size() > 1) {
queue2.offer(queue1.poll());
}
return queue1.poll();
}
}
/**
* Get the top element.
*/
public int top() {
int top = 0;
if (queue1.isEmpty()) {
while (queue2.size() > 1) {
queue1.offer(queue2.poll());
}
top = queue2.poll();
queue1.offer(top);
} else {
while (queue1.size() > 1) {
queue2.offer(queue1.poll());
}
top = queue1.poll();
queue2.offer(top);
}
return top;
}
/**
* Returns whether the stack is empty.
*/
public boolean empty() {
return queue2.isEmpty() && queue1.isEmpty();
}
}
柱形圖中的最大面積
解法一:暴力枚舉高度
外層循環枚舉每個節點
內層循環枚舉從當前節點開始的後面每個節點,每當枚舉一個節點就計算一次最低高度和最大面積
class Solution {
public int largestRectangleArea(int[] heights) {
int maxarea = 0;
for (int i = 0; i < heights.length; i++) {
int minheight = Integer.MAX_VALUE;
for (int j = i; j < heights.length; j++) {
minheight = Math.min(minheight,heights[j]);
maxarea = Math.max(maxarea,minheight*(j-i+1));
}
}
return maxarea;
}
}
解法二:單調棧
官方題解,玩法太高端了,常看看
public class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if (len == 0) return 0;
if (len == 1) return heights[0];
int maxSize = 0;
Stack<Integer> stack = new Stack<>();
stack.push(-1);
for (int i = 0; i < len; i++) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
maxSize = Math.max(maxSize, heights[stack.pop()] * (i - stack.peek() - 1));
}
stack.push(i);
}
while (stack.peek() != -1) {
maxSize = Math.max(maxSize, heights[stack.pop()] * (heights.length - stack.peek() - 1));
}
return maxSize;
}
}
接雨水
壓棧出棧
總體的原則就是:
-
當前高度小於等於棧頂高度,入棧,指針後移。
-
當前高度大於棧頂高度,出棧,計算出當前牆和棧頂的牆之間水的多少,然後計算當前的高度和新棧的高度的關係,重複第 2 步。直到當前牆的高度不大於棧頂高度或者棧空,然後把當前牆入棧,指針後移。
public class Solution {
public int trap(int[] height) {
int sum = 0;
Stack<Integer> stack = new Stack<>();
int current = 0;
while (current < height.length) {
//如果棧不爲空且當前指向的高度大於棧頂高度就一直循環
while (!stack.empty() && height[current] > height[stack.peek()]) {
int h = height[stack.pop()];//要出棧的元素
if (stack.isEmpty()) {//爲空就存不了水
break;
}
int distance = current - stack.peek() - 1;//兩堵牆之間的距離
int min = Math.min(height[stack.peek()], height[current]);
sum += distance * (min - h);
}
stack.push(current);//當前牆入棧
current++;//指針後移
}
return sum;
}
}
每日溫度
運用棧,如果小於棧頂值存入棧,如果大於棧頂的值就將棧頂元素出棧,然後計算距離存入結果數組,反覆出棧直到不滿足大於棧頂元素
public class Solution {
public int[] dailyTemperatures(int[] T) {
Stack<Integer> stack = new Stack<>();
int[] res = new int[T.length];
for (int i = 0; i < T.length; i++) {
while (!stack.isEmpty() && T[i] > T[stack.peek()]) {
Integer pre = stack.pop();
res[pre] = i-pre;
}
stack.push(i);
}
return res;
}
}
下一個更大元素II
和每日溫度類似,只是循環鏈表用兩倍數組長度求模來模擬了
public class Solution {
public int[] nextGreaterElements(int[] nums) {
int len = nums.length;
int[] res = new int[len];
Arrays.fill(res, -1);
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < 2 * len; i++) {
while (!stack.isEmpty() && nums[i % len] > nums[stack.peek() % len]) {
Integer pre = stack.pop();
res[pre % len] = nums[i % len];
}
stack.push(i);
}
return res;
}
}