leetCode--栈和队列理论知识和经典题目汇总

目录

一:栈的理论知识

二:队列的理论知识

题目一:有效的括号

题目二:柱状图中最大的矩形

题目三:滑动窗口最大值

题目四:检查替换后的词是否有序

题目四:棒球比赛

题目五:括号的分数

题目六:每日温度

题目七:反转没对括号间的字串


一:栈的理论知识

因为栈的理论很简单,主要是考察熟练度的问题。

栈的应用:最近相似性(从内向外或者从外向内)

                  公平性(先来先到)

编程:目前Java中一般使用双向队列构造栈和队列

//原始方法 :下面操作由这个定义来讲的
Stack<Integer> stack = new Stack<Integer>();

//目前常用方法 :它的常见操作见双端队列即可
Deque<String> stack = new LinkedList<String>();

 stack有哪些具体操作:

  • push()  :进栈
  • pop(): 出栈
  • peek():看看栈顶元素(不取走)
  • empty():判断栈是否为空。

【注意】:判断栈stack(stack实现)的时候用的是empty(),

                  判断队列(Linkedlist实现)是否为空,使用的是isEmpty().

二:队列的理论知识

队列分为单向队列和双向队列

讲清楚双向队列的操作,单项队列就完全OK了

双端队列的定义:

Deque<Integer> deque = new LinkedList<Integer>();

// 单纯的单项队列也可以定义为
Queue<Integer> queue = new LinkedList<Integer>();

 双端队列的操作:

  • addFirst()  
  • addLast()
  • removeFirst()
  • removeLast()
  • getFirst()
  • getLast()
  • size()

同样的定义,对于队列,即Queue,也可以用上述双端队列的操作,或者使用更简洁的操作

  • add()
  • remove()
  • peek()

题目一:有效的括号

(https://leetcode-cn.com/problems/valid-parentheses/)

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

示例 1:

输入: "()"
输出: true
示例 2:

输入: "()[]{}"
输出: true
示例 3:

输入: "(]"
输出: false
示例 4:

输入: "([)]"
输出: false
示例 5:

输入: "{[]}"
输出: true

官方解题思路简述:使用栈和哈希表

其中对于左的括号压进栈中。哈希表的key存储右侧的括号,哈希表的value存储左侧的括号。

所以字符不在哈希表中,表明字符是左侧的,需要进栈,否则进行后续比较

Java源代码:

import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;

public class stack2 {
    public static void main(String[] args) {
        String s = "(";
        Deque<Character> stack = new LinkedList<Character>();
        Map<Character,Character> hashtable = new HashMap<Character,Character>();
        hashtable.put(')','(');
        hashtable.put(']','[');
        hashtable.put('}','{');
        char ch;
        for(int i =0;i<s.length();i++){
            ch = s.charAt(i);
            if(hashtable.containsKey(ch)){
                if(stack.isEmpty() || stack.peek() != hashtable.get(ch)){
                    System.out.println("no");
                }else {
                    stack.pop();
                }
            }
            else{
                stack.push(ch);
            }
        }
        if(stack.isEmpty()){
            System.out.println("yes");
        }
        else{
            System.out.println("no");
        }

    }
}

【注意1】:最后比较的是栈顶元素和hashtable.get(ch)进行比较,而不是栈顶元素和ch比较

【注意2】:最后还得判断栈是否为空,因为存在输入样例“[”这样的例子,如果栈不为空,则返回false;

第二次写的代码:

class Solution {
    public boolean isValid(String s) {
        Map<Character,Character> map = new HashMap<Character,Character>();
        Deque<Character> stack = new LinkedList<Character>();
        map.put(')','(');
        map.put(']','[');
        map.put('}','{');
        for(int i =0;i<s.length();i++){
            char currentchar = s.charAt(i);
            if(map.containsKey(currentchar)){
                if(map.get(currentchar) == stack.peek()){
                    stack.pop();
                }else{
                    return false;
                }
            }else{
                stack.push(currentchar);
            }
        }
        if(stack.isEmpty()){
            return true;
        }else{
            return false;
        }


    }
}

解释:使用栈和hashmap这两种数据结构进行操作。 

题目二:柱状图中最大的矩形

(链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

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

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

示例:

输入: [2,1,5,6,2,3]
输出: 10

自己的方法:暴力法:枚举左边界,右边界,找到左右边界中高度最小的高度 

结果超时。

public class maxarea {
    public static void main(String[] args) {
        int[] heights = new int[]{0,9};
        int maxarea = 0;
        for (int i = 0; i < heights.length; i++) {
            for (int j = i; j < heights.length; j++) {
                int minheight = Integer.MAX_VALUE;
                for(int k = i; k<=j;k++){
                    if(minheight > heights[k]){
                        minheight = heights[k];
                        System.out.println("minheight: "+i);
                    }
                }
                int temparea = minheight * (j-i+1);
                if(maxarea < temparea){
                    maxarea = temparea;
                }
            }
        }
        System.out.println("maxarea: "+maxarea);
    }
}

官方思路:单调栈:费脑子,还是要反复思考

class Solution {
    public int largestRectangleArea(int[] heights) {
       
        int res = 0;

        // 单调栈:栈底到栈顶由小到大
        Deque<Integer> stack = new LinkedList<>();

        // 矩形的左右边界
        int l, r;

        for (r = 0; r < heights.length; r++) {

            // 它的起始位置等于最后一个弹出的 index
            l = r;
            while (!stack.isEmpty() && heights[stack.peek()] > heights[r]) {

                // 弹出的比当前大的数,它不可能再变长了,计算长度
                l = stack.pop();
                res = Math.max((r - l) * heights[l], res);
            }

            heights[l] = heights[r];
            stack.push(l);
        }

        // 处理栈中剩余的元素
        while (!stack.isEmpty()) {
            int index = stack.pop();
            res = Math.max((r - index) * heights[index], res);
        }

        return res;

    }
}

题目三:滑动窗口最大值

(链接:https://leetcode-cn.com/problems/sliding-window-maximum

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 1:

输入: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
示例 2:

输入:nums = [1], k = 1
输出:[1]
示例 3:

输入:nums = [1,-1], k = 1
输出:[1,-1]
示例 4:

输入:nums = [9,11], k = 2
输出:[11]

自己的思路:枚举每个滑动窗口,并且找到其中的最大值:结果超时

Java源代码

import java.util.ArrayList;
import java.util.List;

public class slidewindow {
    public static void main(String[] args) {
        int[] nums = new int[]{1,3,-1,-3,5,3,6,7};
        int k =3;
        int[] result = new int[nums.length-k+1];
        for (int i = 0; i < nums.length-k+1; i++) {
            int every_maxvalue=Integer.MIN_VALUE;
            for (int j = i; j < i+k; j++) {
                if(every_maxvalue < nums[j]){
                    every_maxvalue = nums[j];
                }
            }
            result[i] = every_maxvalue;
        }
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);

        }
    }

}

官方思路:还是有点难理解,后续再思考

题目四:检查替换后的词是否有序

(2021/1/9)链接:

给定有效字符串 "abc"。

对于任何有效的字符串 V,我们可以将 V 分成两个部分 X 和 Y,使得 X + Y(X 与 Y 连接)等于 V。(X 或 Y 可以为空。)那么,X + "abc" + Y 也同样是有效的。

例如,如果 S = "abc",则有效字符串的示例是:"abc","aabcbc","abcabc","abcabcababcc"。无效字符串的示例是:"abccba","ab","cababc","bac"。

如果给定字符串 S 有效,则返回 true;否则,返回 false。

示例 1:

输入:"aabcbc"
输出:true
解释:
从有效字符串 "abc" 开始。
然后我们可以在 "a" 和 "bc" 之间插入另一个 "abc",产生 "a" + "abc" + "bc",即 "aabcbc"。
示例 2:

输入:"abcabcababcc"
输出:true
解释:
"abcabcabc" 是有效的,它可以视作在原串后连续插入 "abc"。
然后我们可以在最后一个字母之前插入 "abc",产生 "abcabcab" + "abc" + "c",即 "abcabcababcc"。
示例 3:

输入:"abccba"
输出:false
示例 4:

输入:"cababc"
输出:false

官方思路:使用栈,进行栈的值与当前字符串进行比较。一旦遇到当前字符为:“c”就去看栈里面的数据,否则字符入栈。

Java源代码

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.util.Deque;
import java.util.LinkedList;

public class abc {
    public static void main(String[] args) {
        String S ="aabcbc";
        Deque<Character> stack = new LinkedList<Character>();
        for(int i = 0;i<S.length();i++){
            char ch = S.charAt(i);
            if(ch == 'c'){
                System.out.println(stack);
                System.out.println("=====");
                if(stack.isEmpty()||stack.removeLast() != 'b' ){
                    System.out.println("="+stack);
                    System.out.println("no1");;
                }
                System.out.println("== "+stack);
                if(stack.isEmpty()||stack.removeLast()!= 'a'  ){
                    System.out.println("no2");;
                }
            }else{
                stack.add(ch);
            }
            if(stack.isEmpty()){
                System.out.println("yes");
            }
        }
    }
}

第二次写的代码

class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new LinkedList<Character>();
        for(int i =0;i<s.length();i++){
            char currentchar = s.charAt(i);
            if(currentchar == 'c'){
                int flag =0;
                if(!stack.isEmpty()){
                    if(stack.peek() == 'b'){
                        flag +=1;
                        stack.pop();
                    }
                    else{
                        return false;
                    }
                }else{
                    return false;
                }
                if(!stack.isEmpty()){
                    if(stack.peek() == 'a'){
                        flag +=1;
                        stack.pop();
                    }
                    else{
                        return false;
                    }
                }else{
                    return false;
                }
                
            }else{
                stack.push(currentchar);
            }
        }
        if(stack.isEmpty()){
            return true;
        }else{
            return false;
        }

    }
}

 

题目四:棒球比赛

(链接:https://leetcode-cn.com/problems/baseball-game/

你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。

比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops,其中 ops[i] 是你需要记录的第 i 项操作,ops 遵循下述规则:

整数 x - 表示本回合新获得分数 x
"+" - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。
"D" - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。
"C" - 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
请你返回记录中所有得分的总和。

示例 1:

输入:ops = ["5","2","C","D","+"]
输出:30
解释:
"5" - 记录加 5 ,记录现在是 [5]
"2" - 记录加 2 ,记录现在是 [5, 2]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5].
"D" - 记录加 2 * 5 = 10 ,记录现在是 [5, 10].
"+" - 记录加 5 + 10 = 15 ,记录现在是 [5, 10, 15].
所有得分的总和 5 + 10 + 15 = 30
示例 2:

输入:ops = ["5","-2","4","C","D","9","+","+"]
输出:27
解释:
"5" - 记录加 5 ,记录现在是 [5]
"-2" - 记录加 -2 ,记录现在是 [5, -2]
"4" - 记录加 4 ,记录现在是 [5, -2, 4]
"C" - 使前一次得分的记录无效并将其移除,记录现在是 [5, -2]
"D" - 记录加 2 * -2 = -4 ,记录现在是 [5, -2, -4]
"9" - 记录加 9 ,记录现在是 [5, -2, -4, 9]
"+" - 记录加 -4 + 9 = 5 ,记录现在是 [5, -2, -4, 9, 5]
"+" - 记录加 9 + 5 = 14 ,记录现在是 [5, -2, -4, 9, 5, 14]
所有得分的总和 5 + -2 + -4 + 9 + 5 + 14 = 27
示例 3:

输入:ops = ["1"]
输出:1

提示:

1 <= ops.length <= 1000
ops[i] 为 "C"、"D"、"+",或者一个表示整数的字符串。整数范围是 [-3 * 104, 3 * 104]
对于 "+" 操作,题目数据保证记录此操作时前面总是存在两个有效的分数
对于 "C" 和 "D" 操作,题目数据保证记录此操作时前面总是存在一个有效的分数

自己的思路:很简单,使用栈即可

在编译器中写的代码:

import java.util.Stack;

public class ballgame {
    public static void main(String[] args) {
        //String[] ops = {"5","2","C","D","+"};
        String[] ops ={"5","-2","4","C","D","9","+","+","C"};
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < ops.length; i++) {
            String curr = ops[i];
            if(curr == "C"){
                System.out.println("yes");
                stack.pop();
            }
            else if(curr == "D"){
                stack.push(2*stack.peek());
            }else if(curr == "+"){
                int first = stack.pop();
                int second = stack.peek();
                stack.push(first);
                stack.push(first+second);
            }else{
                stack.push(Integer.parseInt(curr));
            }
        }
        System.out.println(stack);
        int sum = 0;
        while(!stack.isEmpty()){
            sum += stack.pop();
        }
        System.out.println(sum);
    }
}

上述字符串比较是否相等我使用的是“==”,结果提交代码通不过,后来改成“equals”,通过了

class Solution {
    public int calPoints(String[] ops) {
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(0);
        for (int i = 0; i < ops.length; i++) {
            String curr = ops[i];
            //if(curr == "C"){
            if(curr.equals("C")){
                stack.pop();
            }
            else if(curr.equals("D")){
                stack.push(2*stack.peek());
            }else if(curr.equals("+")){
                int first = stack.pop();
                int second = stack.peek();
                stack.push(first);
                stack.push(first+second);
            }else{
                stack.push(Integer.valueOf(curr));
            }
        }
        int sum = 0;
        while(!stack.isEmpty()){
            sum += stack.pop();
        }
        return sum;
    }
}

【注意】:Java中两个字符串用“==”比较仅仅是比较地址是否相等,要比较值是否相等还是要使用equals.

题目五:括号的分数

(链接:https://leetcode-cn.com/problems/score-of-parentheses/)

给定一个平衡括号字符串 S,按下述规则计算该字符串的分数:

() 得 1 分。
AB 得 A + B 分,其中 A 和 B 是平衡括号字符串。
(A) 得 2 * A 分,其中 A 是平衡括号字符串。

示例 1:

输入: "()"
输出: 1
示例 2:

输入: "(())"
输出: 2
示例 3:

输入: "()()"
输出: 2
示例 4:

输入: "(()(()))"
输出: 6

官方思路:用栈存储。每次遇见‘(’执行进栈操作。如果遇到‘)’有两种情况,要么是最内层的‘)’,

栈顶元素出来,我们得到结果1,并且加到此时栈顶的结果中,如果不是最内层的

我们把刚刚出栈结果*2加到此时栈顶结果中,把最新的结果放回栈里面去。

Java源代码:

class Solution {
    public int scoreOfParentheses(String S) {
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(0);
        int sum = 0;
        for(char ch: S.toCharArray()){
            if(ch =='('){
                stack.push(0);
            }else{
                int first = stack.pop();
                int second = stack.pop();
                sum=second+Math.max(1,2*first);
                stack.push(sum);
            }
        }
        return stack.pop();
    }
}

【注意】:计算出sum之后,需要进栈。

官方思路:

我们用一个栈来维护当前所在的深度,以及每一层深度的得分。

当我们遇到一个左括号 ( 时,我们将深度加一,并且新的深度的得分置为 0。

当我们遇到一个右括号 ) 时,我们将当前深度的得分乘二并加到上一层的深度。

这里有一种例外情况,如果遇到的是 (),那么得分为1.

class Solution {
    public int scoreOfParentheses(String S) {
        Deque<Integer> stack = new LinkedList<Integer>();
        stack.push(0);
        for(int i=0;i<S.length();i++){
            if(S.charAt(i) == '('){
                stack.push(0);
            }
            else{
                int top1 = stack.pop();
                int top2 = stack.pop();
                int tempsum = top2+ Math.max(top1*2, 1);
                stack.push((tempsum));
            }
        }
        return stack.peek();
    }
}

题目六:每日温度

(链接:https://leetcode-cn.com/problems/daily-temperatures/

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数

方法一:自己的方法:暴力遍历,两重for循环即可解决

Java源代码:
 

public class dailytemporature {
    public static void main(String[] args) {
        int[] T = new int[]{73, 74, 75, 71, 69, 72, 76, 73};
        int[] res = new int[T.length];
        for (int i = 0; i < T.length; i++) {
            int flag = 0;
            for (int j = i+1; j < T.length; j++) {
                if(T[i]<T[j]){
                    flag = 1;
                    res[i] = j-i;
                    break;
                }
            }
            if(flag == 0){
                res[i] = 0;
            }
        }
        for (int i = 0; i < res.length; i++) {
            System.out.println(res[i]);

        }
    }
}

方法二:官方思路:单调栈(递减栈):栈里面存储的是数组的index,而不是数组里面的值,栈不为空的时候,

比较栈顶index对应元素的当前index对应元素的大小。当前index对应元素大的话,表明找到,出栈操作,

返回间隔,找到栈顶index的间隔大小,也就是说不是按照数组顺序依次查找的。

Java源代码:

import java.util.Stack;

public class dailytemporature2 {
    public static void main(String[] args) {
        int[] T = new int[]{55,38,53,81,61,93,97,32,43,78};
        Stack<Integer> stack = new Stack<Integer>();
        int[] res = new int[T.length];
        for (int i = 0; i < T.length-1; i++) {
            int curr = T[i];
            while(!stack.isEmpty() && T[i]>T[stack.peek()]){
                int index = stack.pop();
                res[index] = i-index;
            }
            stack.push(i);
        }
        for (int i = 0; i < res.length; i++) {
            System.out.println(res[i]);

        }
    }
}

 第二次使用单调栈写的代码

class Solution {
    public int[] dailyTemperatures(int[] T) {
        Deque<Integer> stack = new LinkedList<Integer>();
        int[] res = new int[T.length];
        for(int i =0;i<T.length;i++){
            while(!stack.isEmpty() && T[stack.peek()]<T[i]){
                int index = stack.pop();
                res[index] = i - index;
            }
            stack.push(i);
        }
        return res;
    }
}

题目七:反转没对括号间的字串

(链接:https://leetcode-cn.com/problems/reverse-substrings-between-each-pair-of-parentheses/

给出一个字符串 s(仅含有小写英文字母和括号)。

请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。

注意,您的结果中 不应 包含任何括号。

 

示例 1:

输入:s = "(abcd)"
输出:"dcba"
示例 2:

输入:s = "(u(love)i)"
输出:"iloveu"
示例 3:

输入:s = "(ed(et(oc))el)"
输出:"leetcode"
示例 4:

输入:s = "a(bcdefghijkl(mno)p)q"
输出:"apmnolkjihgfedcbq"

思路:多次使用栈结构,遇见‘)’就进行操作。

Java源代码

class Solution {
    public String reverseParentheses(String S) {
        String res="";
        Stack<Character> stack = new Stack<Character>();
        for (int i = 0; i < S.length(); i++) {

            Queue<Character> tempqueue = new LinkedList<Character>();
            char ch = S.charAt(i);
            //System.out.println("此时走到为: "+ch);
            if(ch == ')'){
                //System.out.println("yes");
                while(stack.peek() != '('){
                    char currch = stack.pop();
                    tempqueue.add(currch);
                }
                stack.pop();
                //System.out.println("tempqueue: "+tempqueue);
                while(!tempqueue.isEmpty()){
                    char curr2 = tempqueue.poll();
                    stack.push(curr2);
                }
            }else{
                //System.out.println("ch: "+ch);
                stack.push(ch);
            }

        }
        Stack<Character> resq = new Stack<>();
        while(!stack.isEmpty()){
             resq.push(stack.pop());
        }
        while (!resq.isEmpty()){
            res+=resq.pop();
        }
        
        return res;
        //return stack;
        
        //System.out.println("stack: "+stack);

    }
}

方法二:

采用栈存储字符串中左括号(的位置,每次遇到左括号(,依次进栈,当遇到右括号),把

栈顶元素对应的位置一直到右括号前的位置进行翻转。遍历整个数组结束即可。

class Solution {
    public String reverseParentheses(String s) {
        StringBuffer res = new StringBuffer();
        Deque<Integer> stack = new  LinkedList<Integer>();
        Deque<Character> stackres = new LinkedList<Character>();
        char[] chs = s.toCharArray();
        for(int i =0;i<s.length();i++){
            if(s.charAt(i) == '('){
                stack.push(i);
            }
            if(s.charAt(i) == ')'){
                reversestr(chs,stack.pop()+1,i-1);
            }
        }
        for(int k =0;k<chs.length;k++){
             if((chs[k] !='(') && ( chs[k]!= ')')){
                 res.append(chs[k]);
             }
        }
       
        return res.toString();
    }
    public void reversestr(char[] chs,int left,int right){
        while(left<right){
            char temp = chs[left];
            chs[left] = chs[right];
            chs[right] = temp;
            left++;
            right--;
        }
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值