• 【Java】想进大厂?你应该知道的算法经典习题(一)


    ✅作者简介:大家好我是烫嘴的辛拉面,大家可以叫我拉面。🐭🐭
    📜个人主页: weixin_49405762的博客
    📕系列专栏: 经典算法习题集
    🌞为大🔥推荐一款刷题神器哦 👉点击跳转进入网站

    ☀️前言:从今天开始一个新的专栏 经典算法习题集,整理牛客网经典算法的习题练习,我将用java语言来解题。牛客网除了算法题单之外还有其他热门的各种提单,应有尽有,大家快刷起来吧点击跳转进入牛客网

    ✏️数据结构

    ✒️AB1[模板]栈

    题目描述

    请你实现一个栈。
    操作:
    push x:将 加x x\ x 入栈,保证 x x\ x 为 int 型整数。
    pop:输出栈顶,并让栈顶出栈
    top:输出栈顶,栈顶不出栈
    输入描述:
    第一行为一个正整数 n n\ n ,代表操作次数。(1≤n≤100000)(1 \leq n \leq 100000)(1≤n≤100000)
    接下来的 n n\ n ,每行为一个字符串,代表一个操作。保证操作是题目描述中三种中的一种。

    输出描述:
    如果操作为push,则不输出任何东西。
    如果为另外两种,若栈为空,则输出 "error“
    否则按对应操作输出。
    示例1

    输入: 6
    push 1
    pop
    top
    push 2
    push 3
    pop

    输出:1
    error
    3

    解题思路

    首先看清题目要求,并且根据栈先进后出的特性解决题目 1.用到头文件include这样可以省去建栈等操作,除此之外包含有多种函数 2.将题目分为三种情况,可用if,else语句进行分类,继而进行更进一步划分 3.注意L.pop()用于栈顶的清除,并非用于输出,输出有L.top()函数。

    代码实现(Java)

    import java.util.Scanner;
    //自己做了个栈,不过没做太多校验
    public class Main{
        public static void main(String args[]){
            Scanner sc = new Scanner(System.in);
            int size = Integer.valueOf(sc.nextLine());
            Stack stack = new Stack(size);
            String tempStr;
            String[] tempArr;
            for(int i =0;i<size;i++){
                tempStr = sc.nextLine();
                tempArr = tempStr.split(" ");
                if(tempArr[0].equals("push")){
                    stack.push(Integer.valueOf(tempArr[1]));
                }else if(tempArr[0].equals("top")){
                     stack.top();
                }else{
                    stack.pop();
                }
            }
            
        }
            
    }
    
    class Stack{
        int[] stackSpace;
        static int index = -1;
        Stack(int size){
            stackSpace = new int[size];
        }
        
        
        public void push(int number){
            stackSpace[++index] = number;
        }
        
        public void pop(){
            if(index == -1){
                System.out.println("error");
            }else{
                System.out.println(stackSpace[index--]);
            }
        }
        
         public void top(){
            if(index == -1){
                System.out.println("error");
            }else{
                System.out.println(stackSpace[index]);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    ✒️AB2 栈的压入、弹出序列

    题目描述

    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

    1. 0<=pushV.length == popV.length <=1000
    2. -1000<=pushV[i]<=1000
    3. pushV 的所有数字均不相同

    示例1

    输入:[1,2,3,4,5],[4,5,3,2,1]
    返回值:true
    说明:可以通过 push(1)=>push(2)=>push(3)=>push(4)=>pop()=>push(5)=>pop()=>pop()=>pop()=>pop()
    这样的顺序得到[4,5,3,2,1]这个序列,返回true

    示例2

    输入:[1,2,3,4,5],[4,3,5,1,2]
    返回值:false
    说明:由于是[1,2,3,4,5]的压入顺序,[4,3,5,1,2]的弹出顺序,要求4,3,5必须在1,2前压入,且1,2不能弹出,但是这样压入的顺序,1又不能在2之前弹出,所以无法形成的,返回false

    解题思路

    题目要我们判断两个序列是否符合入栈出栈的次序,我们就可以用一个栈来模拟。对于入栈序列,只要栈为空,序列肯定要依次入栈。那什么时候出来呢?自然是遇到一个元素等于当前的出栈序列的元素,那我们就放弃入栈,让它先出来。

    具体做法

    step 1:准备一个辅助栈,两个下标分别访问两个序列。
    step 2:辅助栈为空或者栈顶不等于出栈数组当前元素,就持续将入栈数组加入栈中。
    step 3:栈顶等于出栈数组当前元素就出栈。
    step 4:当入栈数组访问完,出栈数组无法依次弹出,就是不匹配的,否则两个序列都访问完就是匹配的。
    
    • 1
    • 2
    • 3
    • 4

    图示

    在这里插入图片描述

    代码实现(Java):

    import java.util.Stack;
    public class Solution {
        public boolean IsPopOrder(int [] pushA,int [] popA) {
            int n = pushA.length;
            //辅助栈
            Stack<Integer> s = new Stack<>();
            //遍历入栈的下标
            int j = 0;
            //遍历出栈的数组
            for(int i = 0; i < n; i++){
                //入栈:栈为空或者栈顶不等于出栈数组
                while(j < n && (s.isEmpty() || s.peek() != popA[i])){
                    s.push(pushA[j]);
                    j++;
                }
                //栈顶等于出栈数组
                if(s.peek() == popA[i])
                    s.pop();
                //不匹配序列
                else
                    return false;
            }
            return true;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

    ✒️AB3 有效括号序列

    题目描述

    给出一个仅包含字符’(‘,’)‘,’{‘,’}‘,’[‘和’]',的字符串,判断给出的字符串是否是合法的括号序列
    括号必须以正确的顺序关闭,"()“和”()[]{}“都是合法的括号序列,但”(]“和”([)]"不合法。

    数据范围:字符串长度 0≤n≤100000\le n \le 100000≤n≤10000
    要求:空间复杂度 O(n)O(n)O(n),时间复杂度 O(n)O(n)O(n)
    示例1

    输入:“()[]{}”
    返回值:true

    示例2

    输入:“[]”
    返回值:true

    示例3

    输入:“([)]”
    返回值:false

    题目主要信息

    给定一个只包含大中小左右括号的字符串,判断其中括号是否合法
    中小括号的数学顺序与合法无关,只需要每种左括号在右边有相应匹配的右括号即可,不可交叉匹配,应该是括号嵌套
    
    • 1
    • 2

    解题思路:

    括号的匹配规则应该符合先进后出原理:最外层的括号即最早出现的左括号,也对应最晚出现的右括号,即先进后出,因此可以使用同样先进后出的栈:遇到左括号就将相应匹配的右括号加入栈中,后续如果是合法的,右括号来的顺序就是栈中弹出的顺序。

    具体做法

    step 1:创建辅助栈,遍历字符串。
    step 2:每次遇到小括号的左括号、中括号的左括号、大括号的左括号,就将其对应的呦括号加入栈中,期待在后续遇到。
    step 3:如果没有遇到左括号但是栈为空,说明直接遇到了右括号,不合法。
    step 4:其他情况下,如果遇到右括号,刚好会与栈顶元素相同,弹出栈顶元素继续遍历。
    step 5:理论上,只要括号是匹配的,栈中元素最后是为空的,因此检查栈是否为空即可最后判断是否合法。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    图示

    在这里插入图片描述

    代码实现(java)

    import java.util.*;
    public class Solution {
        public boolean isValid (String s) {
            //辅助栈
            Stack<Character> st = new Stack<Character>(); 
            //遍历字符串
            for(int i = 0; i < s.length(); i++){ 
                //遇到左小括号
                if(s.charAt(i) == '(') 
                    //期待遇到右小括号
                    st.push(')'); 
                //遇到左中括号
                else if(s.charAt(i) == '[') 
                    //期待遇到右中括号
                    st.push(']'); 
                //遇到左打括号
                else if(s.charAt(i) == '{') 
                    //期待遇到右打括号
                    st.push('}'); 
                //必须有左括号的情况下才能遇到右括号
                else if(st.isEmpty() || st.pop() != s.charAt(i)) 
                    return false;
            }
            //栈中是否还有元素
            return st.isEmpty(); 
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    ✒️AB4 逆波兰表达式求值

    题目描述

    给定一个逆波兰表达式,求表达式的值。
    数据范围:表达式长度满足 1≤n≤104 1 \le n \le 10^4 \ 1≤n≤104 ,表达式中仅包含数字和 + ,- , * , / ,其中数字的大小满足 ∣val∣≤200 |val| \le 200 \ ∣val∣≤200 。
    示例1

    输入:[“2”,“1”,“+”,“4”,“*”]
    返回值:12

    示例2

    输入:[“2”,“0”,“+”]
    返回值:2

    解题思路

    逆波兰表达式求值的过程可以借助栈来求解,在遍历数组的时候,判断当前是否是数字,如果是就压入栈中,不是说明遇到了运算符,从栈中弹出两个数字进行运算即可。

    图示

    在这里插入图片描述

    代码实现(java)

    import java.util.*;
    
    
    public class Solution {
        /**
         * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
         *
         * 
         * @param tokens string字符串一维数组 
         * @return int整型
         */
        public int evalRPN (String[] tokens) {
            // 栈
            Stack<Integer> stack = new Stack<Integer>();
            // 长度
            int n = tokens.length;
            // 遍历
            for (int i = 0; i < n; i++) {
                String token = tokens[i];
                // 说明是数字,则押入栈
                if (isNumber(token)) {
                    stack.push(Integer.parseInt(token));
                }
                // 说明遇到运算符
                else {
                    // 弹出两个元素
                    int num2 = stack.pop();
                    int num1 = stack.pop();
                    //判断+ - * /
                    switch (token) {
                        case "+":
                            stack.push(num1 + num2);
                            break;
                        case "-":
                            stack.push(num1 - num2);
                            break;
                        case "*":
                            stack.push(num1 * num2);
                            break;
                        case "/":
                            stack.push(num1 / num2);
                            break;
                        default:
                    }
                }
            }
            return stack.pop();
        }
        // 用于判断token是数字还是运算符
        public boolean isNumber(String token) {
            return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    在这里插入图片描述

    ✒️AB5 点击消除

    题目描述

    牛牛拿到了一个字符串。
    他每次“点击”,可以把字符串中相邻两个相同字母消除,例如,字符串"abbc"点击后可以生成"ac"。
    但相同而不相邻、不相同的相邻字母都是不可以被消除的。
    牛牛想把字符串变得尽可能短。他想知道,当他点击了足够多次之后,字符串的最终形态是什么?
    输入描述:
    一个字符串,仅由小写字母组成。(字符串长度不大于300000)
    输出描述:
    一个字符串,为“点击消除”后的最终形态。若最终的字符串为空串,则输出0。
    示例1

    输入:abbc
    输出:ac

    示例2

    输入:abba
    输出:0

    示例3

    输入:bbbbb
    输出:b

    解题思路

    分为两步来解决:

    1.比较消除相同的字符

    2.顺序输出不同的字符

    步骤1:

    遍历字符,放入栈中。当栈为空栈时(也就是遍历第一次字符的时候,此时栈为空)和栈顶元素和当前遍历的字符不相等时,将该字符放入栈中。
    反之说明当前遍历的字符和栈顶字符是相同的,那么消除(移除)

    步骤2:

    判断栈是否为空,为空说明全部消除,不为空则顺序输出,因为栈是先进后出,这里要保证顺序的话,可以把当前栈的字符放入另外一个栈,然后再输出即保证顺序输出。

    代码实现(java)

    import java.util.Stack;
    
    
    public class Solution2 {
        public static void main(String[] args) {
            eliminate("tsirhvtujuzdnwprhoihkzvckc");
            System.out.println();
            System.out.println("-----------------");
            eliminate("abba");
        }
    
        /**
         *
         * @param s string字符串
         * @return bool布尔型
         */
        public static void eliminate (String s) {
            if (s == null || s == ""){
                return;
            }
            char[] chars = s.toCharArray();
            Stack<Character> stack = new Stack<>();
            for (int i = 0;i<chars.length;i++){
                if (stack.isEmpty() || stack.peek() != chars[i]){
                    stack.push(chars[i]);
                }else {
                    stack.pop();
                }
            }
    
            if (stack.isEmpty()){
                System.out.println("ok");
            }else {
                // 目的是为了顺序输出
                Stack<Character> stack2 = new Stack<>();
                while (!stack.isEmpty()){
                    stack2.push(stack.pop());
                }
                while (!stack2.isEmpty()){
                    System.out.print(stack2.pop());
                }
            }
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    ✒️AB6 表达式求值

    题目描述

    请写一个整数计算器,支持加减乘三种运算和括号。
    数据范围:0≤∣s∣≤1000\le |s| \le 1000≤∣s∣≤100,保证计算结果始终在整型范围内
    要求:空间复杂度: O(n)O(n)O(n),时间复杂度 O(n)O(n)O(n)
    示例1

    输入:“1+2”
    返回值:3

    示例2

    输入:“(2*(3-4))*5”
    返回值:-10

    示例3

    输入:“3+234-1”
    返回值:26

    题目的主要信息

    写一个支持+ - *三种符号的运算器,其中优先级+ - 是一级,*更高一级
    支持括号运算
    
    • 1
    • 2

    解题思路:

    对于上述两个要求,我们要考虑的是两点,一是处理运算优先级的问题,二是处理括号的问题。
    处理优先级问题,那必定是乘号有着优先运算的权利,加号减号先一边看,我们甚至可以把减号看成加一个数的相反数,则这里只有乘法和加法,那我们优先处理乘法,遇到乘法,把前一个数和后一个数乘起来,遇到加法就把这些数字都暂时存起来,最后乘法处理完了,就剩余加法,把之前存起来的数字都相加就好了。
    处理括号的问题,我们可以将括号中的部分看成一个新的表达式,即一个子问题,因此可以将新的表达式递归地求解,得到一个数字,再运算:

    终止条件: 每次遇到左括号意味着进入括号子问题进行计算,那么遇到右括号代表这个递归结束。
    返回值: 将括号内部的计算结果值返回。
    本级任务: 遍历括号里面的字符,进行计算。
    
    • 1
    • 2
    • 3

    具体做法

    step 1:使用栈辅助处理优先级,默认符号为加号。
    step 2:遍历字符串,遇到数字,则将连续的数字字符部分转化为int型数字。
    step 3:遇到左括号,则将括号后的部分送入递归,处理子问题;遇到右括号代表已经到了这个子问题的结尾,结束继续遍历字符串,将子问题的加法部分相加为一个数字,返回。
    step 4:当遇到符号的时候如果是+,得到的数字正常入栈,如果是-,则将其相反数入栈,如果是*,则将栈中内容弹出与后一个元素相乘再入栈。
    step 5:最后将栈中剩余的所有元素,进行一次全部相加。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    图示

    在这里插入图片描述

    代码实现(java)

    import java.util.*;
    public class Solution {
        public ArrayList<Integer> function(String s, int index){
            Stack<Integer> stack = new Stack<Integer>(); 
            int num = 0;
            char op = '+';
            int i;
            for(i = index; i < s.length(); i++){
                //数字转换成int数字
                //判断是否为数字
                if(s.charAt(i) >= '0' && s.charAt(i) <= '9'){ 
                    num = num * 10 + s.charAt(i) - '0';
                    if(i != s.length() - 1)
                        continue;
                }
                //碰到'('时,把整个括号内的当成一个数字处理
                if(s.charAt(i) == '('){
                    //递归处理括号
                    ArrayList<Integer> res = function(s, i + 1);
                    num = res.get(0);
                    i = res.get(1);
                    if(i != s.length() - 1)
                        continue;
                }            
                switch(op){
                //加减号先入栈
                case '+': 
                    stack.push(num);
                    break;
                case '-':
                    //相反数
                    stack.push(-num);
                    break;
                //优先计算乘号
                case '*':  
                    int temp = stack.pop();
                    stack.push(temp * num);
                    break;
                }
                num = 0;
                //右括号结束递归
                if(s.charAt(i) == ')') 
                    break; 
                else 
                    op = s.charAt(i);
            }
            int sum = 0;
            //栈中元素相加
            while(!stack.isEmpty())  
                sum += stack.pop();
            ArrayList<Integer> temp = new ArrayList<Integer>();
            temp.add(sum);
            temp.add(i);
            return temp; 
        }
        public int solve (String s) {
            ArrayList<Integer> res = function(s, 0);
            return res.get(0);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    在这里插入图片描述

  • 相关阅读:
    2022年最新四川机动车签字授权人模拟试题及答案
    隧道HTTP API使用教程
    基于PCA的特征提取和两级匹配的激光雷达SLAM(翻译)
    【系统架构设计】计算机公共基础知识: 2 计算机系统基础知识
    2022年戴森设计大奖中国赛区三强揭晓 着眼世界问题,提出解决方案
    计算机毕业设计之java+ssm王道考研购物网站
    input 的 placeholder 样式
    打开深度学习的锁:(1)入门神经网络
    return 关键字
    git命令
  • 原文地址:https://blog.csdn.net/weixin_49405762/article/details/126628816