牛牛与后缀表达式

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网

题目描述

给定牛牛一个后缀表达式s,计算它的结果,例如,1+1对应的后缀表达式为1#1#+,‘#’作为操作数的结束符号。

其中,表达式中只含有‘+’、’-‘、’*‘三种运算,不包含除法。

本题保证表达式一定合法,且计算过程和计算结果的绝对值一定不会超过101810^{18}1018

示例1

输入

"1#1#+"

返回值

2

说明

1#1#+这个后缀表达式表示的式子是1+1,结果为2

备注:

1≤表达式中操作数≤1091\leq表达式中操作数\leq10^91≤表达式中操作数≤109

1≤表达式长度≤1061\leq表达式长度\leq10^61≤表达式长度≤106

解题思路

因为刚刚才了解完栈这个数据结构,然后刷视频刷到了逆波兰表达式求值,然后就在牛客上找了题做一做。

这道题我是用数据结构栈来做的。

接触的第一道逆波兰表达式求值是在b站上刷视频刷到的,那个题目是力扣150题:

. - 力扣(LeetCode)

上面这道力扣题,我自己感觉输入相对来说较为友好,因为它是以字符串数组的形式给的,这就避免了"数字分家"的情况。

这两道题的解题思路本质思想基本相似,都是运用栈数据结构,然后遍历输入,遇到数字压入栈,遇到运算符时,将栈中元素弹出两次,然后进行计算,再把计算结果压入栈中,最后返回栈中第一个元素即可。

运用栈数据结构

我是直接用java内置的栈。

Stack<Long> stack = new Stack<>();

因为题中给的数据范围超过了int,所以我们泛型使用Long类型。(常听一些大佬说有爆范围、爆数据啥的,这块还不是特别了解,目前只知道超过int就得用longT__T)。

设置一个截取字符串的标记index,初始化为0

int index = 0;

这种方法是我看了若干个题解后,我理解起来比较容易的一种方法。(其他题解看的时候,由于能力较低,我确实有点没能完全get到代码的精髓,理解不是很透彻。)

因为牛客这题是以"#"为操作数的结束符号,而且输入数据的类型是字符串,与力扣那个字符串数组不同,字符串没法很智能的帮我们把数字、运算符都划分好,我们遍历的时候得到的数据都是单个单个的,所以不如直接利用”#“和index直接截取

在此之前,自己有一些失败的操作:

       1. 失败案例一:我用正则表达式,以"#"为分隔符把输入的字符串变成字符数组,当我自以为思路很妙的时候,提交之后直接就wa了,后来调试一番发现,当出现这种情况"12#+12-3"时,”+“和”12“没法分开。

        2.失败案例二:还打算一个个遍历去判断数字到底是几位数,什么时候运算符后面是数字,没写几行代码,中道崩殂......

遍历输入的数据,找到数字,找到运算符

大致思路:遍历已经输入进来的数据,遇到数字压入栈,遇到运算符时,将栈中元素弹出两个,然后进行计算,再把刚刚的计算结果压入栈中,循环往复,直到遍历结束,然后返回栈中第一个元素。

for(int i = 0;i < str.length();i ++) {
     char c = str.charAt(i);
     if(c == '#') {
         stack.push(Long.parseLong(str.substring(index,i)));
         index = i + 1;
      }
      else if (c == '+') {
           long b = stack.pop();
           long a = stack.pop();
           stack.push(a + b);
           index = i + 1;
      }
      else if (c == '-') {
           long b = stack.pop();
           long a = stack.pop();
           stack.push(a - b);
           index = i + 1;
      }
      else if (c == '*') {
           long b = stack.pop();
           long a = stack.pop();
           stack.push(a * b);
           index = i + 1;
      }
}
return stack.pop();

我们先遍历字符串,用字符c接受每次遍历到的单个字符。

当字符c是 "#" 时,说明我们输入完成了一个整数(但是位数不确定,可能只有个位,可能也有十位百位...)。那么怎么把这个整数给它完整的取出来呢?

第一次发现井号时,#的索引是i,那么[0,i-1]都是数字,所以我们用substring方法直接截取就行。截取到的数字,我们把它压入栈中。

        因为题目说表达式一定合法,如果第一个字符就是运算符的话,那么进入后面的if语句时,栈是空的,调用pop会报错,所以感觉最开始的字符都是数字。所以第一次发现井号调用substring时,参数index = 0;截取完字符串,我们让index = i + 1;即让index表示"#“的下一个字符的索引。

后几次发现井号时,与第一次思路相同,只不过index每一次都要更新成i+1,substring中的参数与第一次发现井号不同,变成了(index,i),所谓的不同,即是此时的index不再等于0。

当碰到运算符时,根据碰到的运算符进入相应的if语句。

        遇到运算符说明肯定有两个数据要用当前运算符进行运算,那两个数据就是前面刚刚被压入栈的两个数据,所以我们只需要操作栈弹出顶部两个元素,进行对应的操作即可。得到的结果我们再压入栈中,然后循环往复,进行下一次的运算或者当作结果输出。

提交的代码部分

public long legalExp (String str) {
        // write code here
        Stack<Long> stack = new Stack<>();
        int index = 0;//用于后续截取字符串
        for(int i = 0;i < str.length();i ++) {
            char c = str.charAt(i);
            if(c == '#') {
                stack.push(Long.parseLong(str.substring(index,i)));
                index = i + 1;
            }
            else if (c == '+') {
                long b = stack.pop();
                long a = stack.pop();
                stack.push(a + b);
                index = i + 1;
            }
            else if (c == '-') {
                long b = stack.pop();
                long a = stack.pop();
                stack.push(a - b);
                index = i + 1;
            }
            else if (c == '*') {
                long b = stack.pop();
                long a = stack.pop();
                stack.push(a * b);
                index = i + 1;
            }
        }
        return stack.pop();

ps:请问大家有没有推荐的算法学习路线呀,比如优先学习什么算法啥的,刚开始接触算法,真挺茫然的现在T__T。

  • 45
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值