Java数据结构_栈_算法题

目录

一、将递归转化为循环

二、括号匹配

三、栈的压入、弹出序列

四、逆波兰表达式求值

五、最小栈--以O(1)时间来获取到他的最小值

PS:关于栈的实现--用链表:​编辑


一、将递归转化为循环

逆序打印链表:

java 复制代码
// 递归方式
void printList(Node head){
    if(null != head){
        printList(head.next);
        System.out.print(head.val + " ");
    }
}

// 循环方式
void printList(Node head){
    if(null == head){
        return;
    }

    Stack<Node> s = new Stack<>();
    // 将链表中的结点保存在栈中
    Node cur = head;
    while(null != cur){
        s.push(cur);
        cur = cur.next;
    }

    // 将栈中的元素出栈
    while(!s.empty()){
        System.out.print(s.pop().val + " ");
    }
}

关于递归的思路,如下图所示:

而关于循环的思路,本质就是利用栈本身后进先出的特点:


二、括号匹配

OJ链接:

https://leetcode.cn/problems/valid-parentheses/description/

要想解决这道题 ,首先我们得明白括号所有的情况有哪些,有了思路,才能够较好地去写代码。

四种情况:

  1. 栈顶和当前i下标的括号不匹配--字符串没有遍历完&&栈中仍存在左括号--false

  2. 字符串便利完成&&栈中没有左括号--true

  3. 字符串便利完成&&(但是)栈中仍然存在左括号--false

4.字符串没有遍历完&&(但是)栈已经空了--false

++而解决这道题的关键思路是:++

将所有的左括号放入栈中,然后一个个取出来与没有放入栈中的右括号进行比较,倘若字符串遍历完并且栈已经为空后,那么代表括号匹配了,返回true,否则返回false

代码如下:

java 复制代码
class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();

        //1.遍历字符串
        for(int i=0; i<s.length(); i++){
            char ch = s.charAt(i);

            //2.判断是左括号放到栈里面
            if(ch == '(' || ch == '[' || ch == '{'){
                stack.push(ch);
            }else{
                //3.他是右括号
                //3.1 此时ch是右括号,但是栈是空的
                if(stack.empty()){
                    return false;
                }

                //3.2此时栈不为空,所以取出栈顶元素进行判断
                //3.2.1匹配
                char ch2 = stack.peek(); //( { [
                if(ch2 == '(' && ch == ')' || ch2 == '[' && ch == ']' || ch2 == '{' && ch == '}'){
                    stack.pop();
                }else{
                    //3.2.2 不匹配
                    return false;
                }
            }
        }
        if(!stack.empty()){
          return false;
        }
        return true;
    }
}

三、栈的压入、弹出序列

来看题目:

OJ链接:https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&&tqId=11174&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

如何思考这道题呢?来看下图:

如上图所示,我们有两个数组,一个pushV用来入栈,一个popV用来出栈

我们这样写代码:

pushV定义一个便利下标 i ,popV定义一个便利下标 j

先让 i 开始走,每走一个就压一个元素入栈,然后再与 popV中 j 下标的元素进行比较,

若相同,则弹出元素,并且让 j 这个下标++,如果顺利的话,当 i 遍历完 pushV.length 长度时,

此时若栈为空,说明此时的压入和弹出序列是匹配的。

PS:需要注意,在判断时 内层循环需要注意 stack 不能为空,这样是为了防止出现空指针异常。

同时也需要保证 j 下标不会越界。

++代码如下:++

java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型一维数组 
     * @param popV int整型一维数组 
     * @return bool布尔型
     */
    public boolean IsPopOrder (int[] pushV, int[] popV) {
        Stack<Integer> stack = new Stack<>();

        int j = 0;

        for(int i=0; i<pushV.length; i++){
            stack.push(pushV[i]);

            while(!stack.empty() && j<popV.length && stack.peek() == popV[j]){
                j++;
                stack.pop();
            }
        }
        return stack.empty();
    }
}

四、逆波兰表达式求值

OJ链接:

https://leetcode.cn/problems/evaluate-reverse-polish-notation/

大家可以先自行去了解一下后缀表达式:

入栈与出栈。

++代码如下:++

java 复制代码
class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();

        for(String str : tokens){
            if(!isOperations(str)){
                //是数字字符串
                stack.push(Integer.parseInt(str));
            }else{
                //是运算符 + - * /
                int val2 = stack.pop();
                int val1 = stack.pop();
                switch(str){
                case "+":
                    stack.push(val1 + val2);
                    break;
                case "-":
                    stack.push(val1 - val2);
                    break;
                case "*":
                    stack.push(val1 * val2);
                    break;
                case "/":
                    stack.push(val1 / val2);
                    break;
                }
            }
        }
        return stack.pop();
    }

    public boolean isOperations(String s){
        if(s.equals("+") || s.equals("*") || s.equals("/") || s.equals("-")){
            return true;
        }
        return false;
    }
}

五、最小栈--以O(1)时间来获取到他的最小值

OJ链接:

https://leetcode.cn/problems/min-stack/

OJ模板:

java 复制代码
class MinStack {

    public MinStack() {
        
    }
    
    public void push(int val) {
        
    }
    
    public void pop() {
        
    }
    
    public int top() {
        
    }
    
    public int getMin() {
        
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

来看思路:题目规定了要在常数时间内检索到最小元素,

所以,我们这里有必要定义两个栈,一个普通栈,一个最小栈,用空间来换时间


++具体的思路可以这么来看:++

一、入栈的过程当中:

  1. 每次存放元素的时候,都要和最小栈的栈顶元素进行比较

val ++<=++ minStack.peek()

特别注意,第一点是小于等于,等于的情况也需要考虑进去,因为假如有两个一样的最小值,那么根据下面出栈的原则,此时以常数时间取出最小值就会出问题

  1. 如果最小栈 第一次存放的时候 是空的 ,那么直接存储

二、出栈:

  1. 每次出栈的时候都要判断最小栈的栈顶元素,如果相同最小栈也得出栈

来看具体的代码实现:

java 复制代码
class MinStack {

public Stack<Integer> stack;
public Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack<>();
        minStack = new Stack<>();
    }
    
    public void push(int val) {
        stack.push(val);
        if(minStack.empty()){
            minStack.push(val);
        }else{
            int topVal = minStack.peek();
            //注意此处一定是<=,千万别漏了=号
            if(val <= topVal){
                minStack.push(val);
            }
        }
    }
    
    public void pop() {
        int popVal = stack.pop();
        if(popVal == minStack.peek()){
            minStack.pop();
        }
    }
    
    //相当于peek方法
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(val);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

PS:关于栈的实现--用链表:

由上图所示,我们之前讲的栈 是以 数组实现的栈,其实链表也可以实现栈;

我们也可以像下面的代码一样,用 LinkedList 来定义栈,LinkedList这个类 自己实现了push、pop等方法:

java 复制代码
public static void main(String[] args) {
    LinkedList<Integer> stack = new LinkedList<>();
    stack.push(1);
}
相关推荐
希望永不加班2 小时前
SpringBoot 主启动类解释:@SpringBootApplication 到底做了什么
java·spring boot·后端·spring
蝎子莱莱爱打怪2 小时前
别再裸用 Claude Code 了!32 个亲测Skills + 8 个 MCP,开发效率直接拉满!
java·后端·claude
野犬寒鸦3 小时前
JVM垃圾回收机制面试常问问题及详解
java·服务器·开发语言·jvm·后端·算法·面试
️是783 小时前
信息奥赛一本通—编程启蒙(3346:【例60.3】 找素数)
数据结构·c++·算法
captain3763 小时前
map和set
数据结构·算法
_杨瀚博3 小时前
JAVA找出哪个类import了不存在的类
java·后端
OKkankan3 小时前
深入理解linux进程
java·linux·c++
java1234_小锋3 小时前
Java高频面试题:Spring-AOP通知和执行顺序?
java·开发语言·spring
番茄去哪了4 小时前
Java基础面试题day02
java·开发语言·面向对象编程