1. 用隊列實現(xiàn)?;螂p棧實現(xiàn)隊列相關(guān)
- 一個隊列實現(xiàn)棧:要彈出,隊尾先存入隊首
class MyStack {
/*
一個隊列實現(xiàn)棧功能
8.23
*/
LinkedList<Integer> queue;
/** Initialize your data structure here. */
public MyStack() {
queue = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
//入隊尾
queue.addLast(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
//要彈出棧頂,隊尾先存入隊首
for(int i=0;i<queue.size()-1;i++){
queue.addLast(queue.pollFirst());
}
return queue.pollFirst();
}
/** Get the top element. */
public int top() {
//要返回棧頂,隊尾先存入隊首
for(int i=0;i<queue.size()-1;i++){
queue.addLast(queue.pollFirst());
}
//先接收隊首
int pre = queue.pollFirst();
//重新入隊尾
queue.addLast(pre);
return pre;
}
/** Returns whether the stack is empty. */
public boolean empty() {
if(queue.size() == 0){
return true;
}else{
return false;
}
}
}
- 雙棧實現(xiàn)隊列
class MyQueue {
/*
雙棧實現(xiàn)隊列,棧先進(jìn)后出,隊列先進(jìn)先出
8.23
*/
Stack<Integer> stack1;
Stack<Integer> stack2;
/** Initialize your data structure here. */
public MyQueue() {
stack1 = new Stack<>();
stack2 = new Stack<>();
}
/** Push element x to the back of queue. */
public void push(int x) {
//stack1直接入棧
stack1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
//當(dāng)stack2為空stack1不為空時,stack2存入stack1的彈出,實現(xiàn)先進(jìn)先出
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
if(stack2.isEmpty()){
return -1;
}else{
return stack2.pop();
}
}
/** Get the front element. */
public int peek() {
//同pop
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
if(stack2.isEmpty()){
return -1;
}else{
return stack2.peek();
}
}
/** Returns whether the queue is empty. */
public boolean empty() {
//判斷stack1和stack2都為空
return stack1.isEmpty() && stack2.isEmpty();
}
}
- 最小棧:包含min的棧
class MinStack {
/*
最小棧:雙棧維護(hù)min
8.24
*/
Stack<Integer> stack;
Stack<Integer> min;
/** initialize your data structure here. */
public MinStack() {
stack = new Stack<>();
min = new Stack<>();
}
public void push(int x) {
//stack直接存
stack.push(x);
//min的棧頂維護(hù)min
if(min.isEmpty() || min.peek() >= x){
min.push(x);
}
}
public void pop() {
//如果stack.pop等于min.peek。min彈出棧頂
if(stack.pop().equals(min.peek())){
min.pop();
}
}
public int top() {
return stack.peek();
}
public int getMin() {
return min.peek();
}
}
- 最大隊列:
class MaxQueue {
/*
隊列的最大值
7.27
*/
LinkedList<Integer> queue;
//max隊首維護(hù)最大值
LinkedList<Integer> max;
public MaxQueue() {
queue = new LinkedList<>();
max = new LinkedList<>();
}
public int max_value() {
//如果queue為空,返回-1,否則返回max隊首
if(queue.isEmpty()){
return -1;
}else{
return max.peekFirst();
}
}
public void push_back(int value) {
queue.addLast(value);
//因為max隊列的隊首維護(hù)最大值,如果當(dāng)前元素比隊尾大,彈出隊尾,將當(dāng)前元素入隊尾,形成從大到小排序的隊列
while(!max.isEmpty() && max.peekLast() <= value){
max.removeLast();
}
max.addLast(value);
}
public int pop_front() {
if(queue.isEmpty()){
return -1;
}
//先接收隊列彈出的隊首
int result = queue.removeFirst();
//判斷彈出的元素與max隊列維護(hù)的最大值是否相等,如果相等,max隊列也要彈出隊首
if(result == max.peekFirst()){
max.removeFirst();
}
//返回隊列的彈出
return result;
}
}
2. 括號匹配類型
- 有效括號(老經(jīng)典了,好幾次筆試都碰到了)
class Solution {
public boolean isValid(String s) {
/*
有效括號
8.24
*/
//單調(diào)棧,當(dāng)遇到左半括號時,存入右半括號,如果棧為空,說明沒有存入,如果棧彈出的不等于下一個字符(右半括號)
Stack<Character> stack = new Stack<>();
char[] str = s.toCharArray();
for(int i=0;i<str.length;i++){
if(str[i] == '('){
stack.push(')');
}else if(str[i] == '['){
stack.push(']');
}else if(str[i] == '{'){
stack.push('}');
}else if(stack.isEmpty() || stack.pop() != str[i]){
//如果棧為空,說明無法存入右半。如果棧頂不等于下一次(右半括號),說明無法閉合
return false;
}
}
return stack.isEmpty();
}
}
- 最長有效括號:
class Solution {
public int longestValidParentheses(String s) {
/*
最長有效括號
8.23
*/
//先預(yù)存-1,用于判斷字符串是否是"))"類型
//當(dāng)遇到"("時,先將其索引入棧
//當(dāng)遇到")"時,彈出棧頂元素,表示已經(jīng)使用右括號匹配左括號,形成一個閉合括號
//如果彈出之后棧為空,說明字符串可能是:"))"這種形式,表明當(dāng)前右括號無法閉合,將其索引重新入棧
//如果彈出之后棧不為空,當(dāng)前索引 - 棧頂。如"(()",當(dāng)遇到)時,彈出棧頂元素1,當(dāng)前索引2 - 0 = 2,就是最長有效括號
Stack<Integer> stack = new Stack<>();
stack.push(-1);
char[] str = s.toCharArray();
int result = 0;
for(int i=0;i<str.length;i++){
if(str[i] == '('){
stack.push(i);
}else{
//一定要先彈出
stack.pop();
if(stack.isEmpty()){
stack.push(i);
}else{
result = Math.max(result,i - stack.peek());
}
}
}
return result;
}
}
3. 單調(diào)棧
- 驗證棧彈出和棧存入
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
/*
驗證棧序列
單調(diào)棧
8.24
*/
Stack<Integer> stack = new Stack<>();
int index = 0;
//遍歷入棧序列
for(int i : pushed){
//先入棧
stack.push(i);
//while循環(huán)判斷,如果相等,彈出棧頂
while(!stack.isEmpty() && stack.peek() == popped[index]){
index++;
stack.pop();
}
}
return stack.isEmpty();
}
}
- 每日溫度
class Solution {
public int[] dailyTemperatures(int[] T) {
/*
每日溫度
7.26
*/
//單調(diào)棧,棧存索引,當(dāng)棧頂比當(dāng)前小時,計算差值
Stack<Integer> stack = new Stack<>();
int[] result = new int[T.length];
for(int i=0;i<T.length;i++){
//棧比數(shù)組慢,當(dāng)棧頂小于當(dāng)前數(shù)組元素時,說明升溫,彈出棧頂,計算其索引差值,存入到result數(shù)組對應(yīng)的索引位置(不是順序存儲啊)
while(!stack.isEmpty() && T[i] > T[stack.peek()]){
int index = stack.pop();
result[index] = i - index;
}
stack.push(i);
}
return result;
}
}
- 柱狀圖的最大矩形
class Solution {
public int largestRectangleArea(int[] heights) {
/*
柱狀圖中最大的矩形
7.24
*/
//單調(diào)棧,先復(fù)制數(shù)組,在頭尾添加一個高度為1的柱體
//判斷空
if(heights.length == 0){
return 0;
}
//復(fù)制數(shù)組,在頭尾插入一個高度為0的主題
int[] temp = new int[heights.length+2];
//從1到temp.length
System.arraycopy(heights,0,temp,1,heights.length);
Stack<Integer> stack = new Stack<>();
int result = 0;
for(int i=0;i<temp.length;i++){
//while棧頂比當(dāng)前大,找到第一個比當(dāng)前小的柱體,計算其體積
while(!stack.isEmpty() && temp[i] < temp[stack.peek()]){
int high = temp[stack.pop()];
int widht = i - stack.peek() - 1;
result = Math.max(high*widht,result);
}
stack.push(i);
}
return result;
}
}
- 接雨水(解法不屬于單調(diào)棧,但還是一類型的經(jīng)典題目,所以放在一起總結(jié))
class Solution {
public int trap(int[] height) {
/*
接雨水
7.24
*/
//左右數(shù)組存最大值,提取左右數(shù)組的最小值,如果最小值比當(dāng)前高度高,疊加雨水量
//判斷空
if(height.length == 0){
return 0;
}
int[] left_max = new int[height.length];
int[] right_max = new int[height.length];
//從左往右搜,提取最大值,從1開始(0不能存水)
for(int i=1;i<height.length;i++){
left_max[i] = Math.max(height[i-1],left_max[i-1]);
}
//從右往左搜,提取最大值,從len-2開始(len-1不能存水)
for(int i=height.length-2;i>=0;i--){
right_max[i] = Math.max(height[i+1],right_max[i+1]);
}
int result = 0;
//從1到len-2
for(int i=1;i<height.length-1;i++){
int low = Math.min(left_max[i],right_max[i]);
//如果low比當(dāng)前高度高,說明可以存水,疊加高度差
if(low > height[i]){
result += low-height[i];
}
}
return result;
}
}
- 滑動窗口的最大值
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
/*
滑動窗口的最大值
8.24
*/
//創(chuàng)建窗口數(shù)組
int len = nums.length;
int[] result = new int[len-k+1];
//創(chuàng)建隊列
LinkedList<Integer> queue = new LinkedList<>();
int index = 0;
for(int i=0;i<nums.length;i++){
//隊尾維護(hù)最大值
while(!queue.isEmpty() && nums[i] > nums[queue.peekLast()]){
queue.removeLast();
}
queue.addLast(i);
//當(dāng)滑動窗口左邊界等于隊首時,說明要右移,隊列彈出隊首
if(i-k == queue.peekFirst()){
queue.removeFirst();
}
//存入:當(dāng)形成滑動窗口之后,添加隊首對應(yīng)的元素
if(i >= k-1){
result[index++] = nums[queue.peekFirst()];
}
}
return result;
}
}