栈部分刷题记录

本文探讨了栈在处理各种计算和解析问题中的应用,包括棒球操作、简化路径、最长绝对路径、逆波兰表达式求值、基本计算器、括号匹配、函数的独占时间和标签验证。通过示例代码展示了如何利用栈解决这些问题,涉及括号匹配、运算符优先级和递归等概念。
摘要由CSDN通过智能技术生成

一、用栈访问最后若干元素

question 682(棒球)、

在这里插入图片描述
answer

class Solution {
    public int calPoints(String[] ops) {
        int res=0;
        int[] arr=new int[ops.length];
        int i=0;
        for(String s:ops){
            switch(s){
                case "+" : arr[i]=arr[i-1]+arr[i-2];i++; break;
                case "D" : arr[i]=2*arr[i-1];i++;break;
                case "C" : arr[i-1]=0;i--;break;
                default : arr[i]=Integer.valueOf(s);i++;
            }
        }
        for(int num:arr){
            res+=num;
        }
        return res;
    }
}

question71(简化路径)、

在这里插入图片描述
answer

class Solution {
    public String simplifyPath(String path) {
        String[] names=path.split("/");
        //java官方推荐栈用双端队列
        Deque<String> stack=new ArrayDeque<String>();
        for(String name:names){
            if("..".equals(name)){
                if(!stack.isEmpty()){
                    stack.pollLast();
                }
            }else if(name.length()>0&&!".".equals(name)){
                stack.offerLast(name);
            }
        }
        StringBuffer ans=new StringBuffer();
        if(stack.isEmpty()){
            ans.append("/");
        }else{
            while(!stack.isEmpty()){
                ans.append("/");
                ans.append(stack.pollFirst());
            }
        }
        return ans.toString();
    }
}

question 388(文件的最长绝对路径)

在这里插入图片描述
在这里插入图片描述
answer

class Solution {
    public int lengthLongestPath(String input) {
        int n = input.length();
        //下标
        int pos = 0;
        //ans记录当前最长的路径
        int ans = 0;
        Deque<Integer> stack = new ArrayDeque<Integer>();
        while (pos < n) {
            /* 检测当前文件(一个文件夹)的深度 */
            int depth = 1;
            //第几级目录就有几个'\t'
            while (pos < n && input.charAt(pos) == '\t') {
                pos++;
                depth++;
            }
            /* 统计当前文件名的长度 */
            boolean isFile = false;  
            int len = 0;   
            while (pos < n && input.charAt(pos) != '\n') {
                if (input.charAt(pos) == '.') {
                    isFile = true;
                }
                len++;
                pos++;
            }
            /* 跳过当前的换行符 */
            pos++;
            //stack.size()应该小于depth,才属于同一级目录,此刻还未插入当前文件长度
            while (stack.size() >= depth) {
                stack.pop();
            }
            //加一是   ’/‘
            if (!stack.isEmpty()) {
                len += stack.peek() + 1;
            }
            if (isFile) {
                ans = Math.max(ans, len);
            } else {
                //文件长度递增的入栈(l1,l2+l1+1,l1+l2+l3+2)
                stack.push(len);
            }
        }
        return ans;
    }
}

二、栈与计算器

question 150(逆波兰表达式求值)、

在这里插入图片描述
answer

class Solution {
    public int evalRPN(String[] tokens) {
        int len=tokens.length;
        Deque<Integer> stack=new ArrayDeque<>();
        String operaters="+-*/";
        for(int i=0;i<len;i++){
            String token=tokens[i];
            if(!operaters.contains(token)){
                //push 添加栈顶
                stack.push(Integer.parseInt(token));
            }else{
                //pop移除栈顶
                int num1=stack.pop();
                int num2=stack.pop();
                switch(token){
                    case "+" : stack.push(num1+num2);break;
                    case "-" : stack.push(num2-num1);break;
                    case "*" : stack.push(num1*num2);break;
                    case "/" : stack.push(num2/num1);break;
                }
            }
        }
        return stack.pop();
    }
}

answer2

class Solution {
    public int evalRPN(String[] tokens) {
        int len=tokens.length;
        Deque<Integer> stack=new ArrayDeque<>();
        
        for(int i=0;i<len;i++){
            String token=tokens[i];
            if(isNumber(token)){
                //push 添加栈顶
                stack.push(Integer.parseInt(token));
            }else{
                //pop移除栈顶
                int num1=stack.pop();
                int num2=stack.pop();
                switch(token){
                    case "+" : stack.push(num1+num2);break;
                    case "-" : stack.push(num2-num1);break;
                    case "*" : stack.push(num1*num2);break;
                    case "/" : stack.push(num2/num1);break;
                }
            }
        }
        return stack.pop();
    }
     public boolean isNumber(String token) {
        return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token));
    }
}

question 227(基本计算器)、

在这里插入图片描述
answer

class Solution {
    //一般需要两个栈,一个数据栈,一个符号栈
    //符号栈用sign代替,只存储上一个符号,乘除直接计算,减变加负数
    public int calculate(String s) {
        //-2  = +(-2)
        //保存上一个符号,初始为+
        char sign='+';
        //当前数
        int num=0;
        Deque<Integer> stack=new LinkedList<>();
        int len=s.length();

        for(int i=0;i<len;i++){
            if(Character.isDigit(s.charAt(i))){
                //可能存在进位的情况
                num=num*10+s.charAt(i)-'0';
            }
            if(!Character.isDigit(s.charAt(i))&&s.charAt(i)!=' '||i==len-1){
                switch(sign){
                    //push从头插入
                    case '+' : stack.push(num);break;
                    case '-' : stack.push(-num);break;
                    case '*' : stack.push(stack.pop()*num); break;
                    case '/' : stack.push(stack.pop()/num); break;
                }
                sign=s.charAt(i);
                num=0;
            }
        }
        //处理stack里面相加的数字
        int ans=0;
        while(!stack.isEmpty()){
            ans+=stack.pop();
        }
        return ans;
    }
}

question224(基本计算器)

在这里插入图片描述
answer

class Solution {
    public int calculate(String s) {
        Deque<Integer> stack=new LinkedList<>();
        //sign 代表正负
        int sign=1;
        int res=0;
        int length=s.length();
        for(int i=0;i<length;i++){
            char ch=s.charAt(i);
            if(Character.isDigit(ch)){
                int cur=ch-'0';
                //可能不是个位数
                while(i+1<length&&Character.isDigit(s.charAt(i+1))){
                    cur=cur*10+s.charAt(++i)-'0';
                }
                //没遇到括号,直接累加
                res=res+cur*sign;
            }else if(ch=='+'){
                sign=1;
            }else if(ch=='-'){
                sign=-1;
            }else if(ch=='('){
                //括号外面已经累加的数,入栈
                stack.push(res);
                res=0;
                stack.push(sign);
                sign=1;
            }else if(ch==')'){
                //res*stack.pop(),弹出的是符号位
                res=res*stack.pop()+stack.pop();
            }
        }
        return res;
    }
}

三、栈与括号匹配

question20(有效的括号)、

在这里插入图片描述
answer

class Solution {
    public boolean isValid(String s) {
        int len=s.length();
        if(len%2!=0){
            return false;
        }

        Map<Character,Character> pairs=new HashMap<>();
        pairs.put(')','(');
        pairs.put(']','[');
        pairs.put('}','{');

        //遇到左括号,入栈,遇到右括号,看栈中是否有对应的左括号
        Deque<Character> stack=new LinkedList<>();

        for(int i=0;i<len;i++){
            char cur=s.charAt(i);
            //如果是右括号
            if(pairs.containsKey(cur)){
                if(stack.isEmpty()||stack.peek()!=pairs.get(cur)){
                    return false;
                }
                stack.pop();
            }else{
                stack.push(cur);
            }
        }
        return stack.isEmpty();
    }
}

answer 2
时间复杂度高,replace o(n)

class Solution {
    public boolean isValid(String s) {
        if(s.length()%2!=0){
            return false;
        }
        int len=s.length()/2;
        for(int i=0;i<len;i++){
            s=s.replace("()","");
            s=s.replace("[]","");
            s=s.replace("{}","");
            if(s.length()==0){
                return true;
            }
        }
        return false;
    }
}

question636(函数的独占时间)、

在这里插入图片描述
在这里插入图片描述

answer

class Solution {
    public int[] exclusiveTime(int n, List<String> logs) {
        //这道题关键是单线程非抢占cpu,就是说父函数调用子函数
        //子函数结束之后、父函数才有可能结束。不会出现父函数结束了,子函数继续运行的情况。
        //即只有最内层的进程出战后,外层进程才可能出栈
        //遇到start入栈,end出栈
        //最内层函数出栈后要判断栈顶是否还有函数,有的话,下一个出栈的就是,要把当前函数的占用时间减掉
        Deque<int[]> stack=new LinkedList<>();
        //n个程序
        int[] res =new int[n];
        for(String log:logs){
            //把每一项用 : 分割开
            String[] s=log.split(":");
            int id=Integer.parseInt(s[0]);
            int time=Integer.parseInt(s[2]);
            //如果是开始时间就入栈
            if("start".equals(s[1])){
                stack.push(new int[]{id,time});
                //如果是结束时间就统计当前id运行的时间
            }else if("end".equals(s[1])){
                //0:id, 1:time
                int[] pop=stack.pop();
                //运行时间=end-start+1;
                int interval=time-pop[1]+1;
                //把当前id的运行时间存储起来
                res[pop[0]]+=interval;
                //下一个进程减去当前运行的时间
                if(!stack.isEmpty()){
                     res[stack.peek()[0]]-=interval;
                }
               
            }
        }
        return res;
    }
}

question591(标签验证器)*、

在这里插入图片描述
answer
在这里插入图片描述
answer

class Solution {
    public boolean isValid(String code) {
        int n = code.length();
        Deque<String> tags = new ArrayDeque<String>();

        int i = 0;
        while (i < n) {
            if (code.charAt(i) == '<') {
                if (i == n - 1) {
                    return false;
                }
                //如果遇到结束符
                if (code.charAt(i + 1) == '/') {
                    //结束符的位置
                    int j = code.indexOf('>', i);
                    if (j < 0) {
                        return false;
                    }
                    //截取结束符的名字
                    String tagname = code.substring(i + 2, j);
                    //与开始符名字比较 是否相等
                    if (tags.isEmpty() || !tags.peek().equals(tagname)) {
                        return false;
                    }
                    tags.pop();
                    i = j + 1;
                    if (tags.isEmpty() && i != n) {
                        return false;
                    }
                } else if (code.charAt(i + 1) == '!') {
                    //如果是[CDATA[
                    if (tags.isEmpty()) {
                        return false;
                    }
                    //  i+9是cdate里面的内容
                    if (i + 9 > n-1) {
                        return false;
                    }
                    String cdata = code.substring(i + 2, i + 9);
                    if (!"[CDATA[".equals(cdata)) {
                        return false;
                    }
                    int j = code.indexOf("]]>", i);
                    if (j < 0) {
                        return false;
                    }
                    //跳过]]>
                    i = j + 3;
                } else {
                    int j = code.indexOf('>', i);
                    if (j < 0) {
                        return false;
                    }
                    String tagname = code.substring(i + 1, j);
                    if (tagname.length() < 1 || tagname.length() > 9) {
                        return false;
                    }
                    for (int k = 0; k < tagname.length(); ++k) {
                        if (!Character.isUpperCase(tagname.charAt(k))) {
                            return false;
                        }
                    }
                    tags.push(tagname);
                    i = j + 1;
                }
            } else {
                if (tags.isEmpty()) {
                    return false;
                }
                ++i;
            }
        }

        return tags.isEmpty();
    }
}

question32(最长有效括号)

在这里插入图片描述
answer

class Solution {
    public int longestValidParentheses(String s) {
        int res=0;
        Deque<Integer> stack=new LinkedList<Integer>();
        //表示最后一个没有被匹配的右括号的下标
        stack.push(-1);
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)=='('){
                stack.push(i);
            }else{
                stack.pop();
                if(stack.isEmpty()){
                    //没有左括号匹配,更新最后一个没有被匹配的右括号下标
                    stack.push(i);
                }else{
                    //匹配
                    res=Math.max(res,i-stack.peek());
                }
            }
        }
        return res;
    }
}

四、递归

question 385(迷你语法分析器)、

在这里插入图片描述
answer

/**
 * // This is the interface that allows for creating nested lists.
 * // You should not implement it, or speculate about its implementation
 * public interface NestedInteger {
 *     // Constructor initializes an empty nested list.
 *     public NestedInteger();
 *
 *     // Constructor initializes a single integer.
 *     public NestedInteger(int value);
 *
 *     // @return true if this NestedInteger holds a single integer, rather than a nested list.
 *     public boolean isInteger();
 *
 *     // @return the single integer that this NestedInteger holds, if it holds a single integer
 *     // Return null if this NestedInteger holds a nested list
 *     public Integer getInteger();
 *
 *     // Set this NestedInteger to hold a single integer.
 *     public void setInteger(int value);
 *
 *     // Set this NestedInteger to hold a nested list and adds a nested integer to it.
 *     public void add(NestedInteger ni);
 *
 *     // @return the nested list that this NestedInteger holds, if it holds a nested list
 *     // Return empty list if this NestedInteger holds a single integer
 *     public List<NestedInteger> getList();
 * }
 */
class Solution {
    //用栈做
    public NestedInteger deserialize(String s) {
        if(s.charAt(0)!='['){
            return new NestedInteger(Integer.parseInt(s));
        }
        Deque<NestedInteger> stack=new ArrayDeque<>();
        int num=0;
        int flage=1;
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);
            if(c=='-'){
                flage=-1;
            }else if(Character.isDigit(c)){
                num=num*10+c-'0';
            }else if(c=='['){
                stack.push(new NestedInteger());
            }else if(c==','||c==']'){
                if(Character.isDigit(s.charAt(i-1))){
                    num*=flage;
                    stack.peek().add(new NestedInteger(num));
                }
               num=0;
               flage=1;
               if(c==']'&&stack.size()>1){
                   NestedInteger ni=stack.pop();
                   stack.peek().add(ni);
               }
            }
        }
        return stack.pop();
    }
}

question341 *、

question 394(字符串解码)

在这里插入图片描述
answer

class Solution {
    /**
     * 双栈解法:
     * 准备两个栈,一个存放数字,一个存放字符串
     * 遍历字符串分4中情况
     * 一、如果是数字 将字符转成整型数字 注意数字不一定是个位 有可能是十位,百位等 
     所以digit = digit*10 + ch - '0';
     * 二、如果是字符 直接将字符放在临时字符串中
     * 三、如果是"[" 将临时数字和临时字符串入栈
     * 四、如果是"]" 将数字和字符串出栈 此时临时字符串res = 出栈字符串 + 出栈数字*res
     */
    public String decodeString(String s) {
      //创建数字栈,创建字符串栈及临时数字和临时字符串
      Deque<Integer> stack_digit=new LinkedList<>();
      Deque<StringBuilder> stack_string=new LinkedList<>();
      int digit=0;
      StringBuilder res=new StringBuilder();
      //遍历字符串分4中情况
      for(int i=0;i<s.length();i++){
          char ch=s.charAt(i);
          if(ch=='['){
            //如果是"["将临时数字和临时字符串入栈
            stack_digit.push(digit);
            stack_string.push(res);
            digit=0;
            res=new StringBuilder();
          }else if(ch==']'){
            //如果是"]"将数字和字符串出栈,此时临时字符串
            //res=出栈字符串+出栈数字*res;
            StringBuilder temp=stack_string.poll();
            int count=stack_digit.poll();
            for(int j=0;j<count;j++){
                temp.append(res.toString());
            }
            res=temp;
          }else if(Character.isDigit(ch)){
              //如果是数字,放入临时数字中
              digit=digit*10+ch-'0';
          }else{
              //如果是字符,直接将字符放在临时字符串中
              res.append(ch);
          }
      }
      return res.toString();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值