当前位置: 首页 > news >正文

力扣面试150题--基本计算器

Day 31

题目描述

在这里插入图片描述

思路

逆波兰表达式扩展
初次思路:此题我遇到了几个难点

  1. 如何处理()
  2. 如何处理-1和2-1中的负数还是减法问题 1-(-(1+2))
  3. 如何处理多余的空格

我的做法如下:根据前面逆波兰表达式求值,可以考虑将这个正常的表达式先转化为逆波兰表达式,再用逆波兰表达式进行求值。具体如下:

  1. 创建num字符串,用于取出表达式中的数字
  2. 创建一个list列表,用来存放转化后的逆波兰表达式
  3. 创建一个栈stack来暂时存放符号
  4. 从前向后遍历表达式
  5. 如果取出来的字符为+,将+压入栈stack
  6. 如果取出来的字符为(,将( 压入栈stack
  7. 如果取出的字符为-,这里比较复杂,分为以下两段解释
  8. 如果此时栈中不为空,可能会出现(-的情况,需要向前回溯,找到第一个不为’ ‘的字符a,同时也需要从-向后遍历,找到一个不是’ ‘的字符b,这两个字符要拿来比较,如果a==‘(’,b='(‘,说明出现的情况为(-(的情况,此时将0存入逆波兰表达式,再将-压入栈,如果出现a==‘(’,b!=‘(’,那么就是(-常数,这里肯定就是负数(因为除了(不能-与任何其他符号连续出现),如果不是以上两种情况,就直接将-压入栈,这是正常的减法。
  9. 如果此时-是第一个出现的符号,此时需要向后遍历,后面出现的是不是(,如果为(,直接将-压入栈(这里后面会处理为0-(),如果其后不为(,说明就是负数
  10. 如果取出的字符为),也要分为两个情况
  11. 如果此时栈非空,并且栈顶为(,直接弹出,连续弹出到为(或者栈为空
  12. 如果此时栈非空,并且栈顶不为(,直接弹出()中的所有符号
  13. 如果取出的字符为’ ‘,不处理直接跳过。
  14. 如果取出来的是数字,使用num拼接,如果下一个不为数字,说明数字拼接完成,将它加入list,同时取出栈顶符号加入表达式(栈非空并且栈顶不为( ),弹出栈顶元素,将num清空;如果下一个还是数字,就不管。
  15. 使用逆波兰求值,这里注意如果取出符号为-,此时数字栈中为空,就变成0-栈顶(原因在于上面的-)
    注意,这里11,12,为什么需要特殊处理这步
    原因在于一个样例:(7)-(0)+(4)
    如果我们只弹出到(,会出现这种情况
    7 0 4 + -
    正确的结果应该是
    7 0 - 4 +
    为什么会出现这种情况,原因在于,-一直被压在栈底,第二个)只取到(就结束了。
class Solution {public int calculate(String s) {String num="";//用来存放从表达式中取出的数字ArrayList<String> list = new ArrayList<>();//存放逆波兰表达式Stack<Character> stack = new Stack<>();//用来暂存符号Stack<Integer> nums = new Stack<>();//用于逆波兰表达式存放数字for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == '+') {//压入栈即可stack.push(c);}else if (c == '-') {if(!stack.isEmpty()){//栈非空int j=i-1;while(s.charAt(j)==' '){//向前遍历找到第一个非空格字符j--;}while (s.charAt(i+1)==' '){//向后遍历找到第一个非空格字符i++;//这里都是空格,直接修改i也没关系}if(s.charAt(j)=='('&&s.charAt(i+1)!='('){//(-常数,说明为负数num=num+c;//负数}else if(s.charAt(j)=='('&&s.charAt(i+1)=='('){//(-(list.add("0");//变成(0-(stack.push(c);//变成减法,-压入栈}else{stack.push(c);//说明就是正常的减法}}else if(i-1<0){//-出现在表达式的第一个while (s.charAt(i+1)==' '){//向后遍历找到第一个非空格字符i++;}if(s.charAt(i+1)=='('){//-( 直接压入栈,后面逆波兰计算时处理stack.push(c);}else{num=num+c;//说明为负数,因为除了(,不可能出现-加上任何符号}}else{stack.push(c);//说明就是正常的减法}}else if (c == '(') {//压入栈即可stack.push(c);}else if (c == ')') {if(!stack.isEmpty()&&stack.peek()=='('){//处理特殊情况(7)-(0)+(4)stack.pop();if(!stack.isEmpty()&&stack.peek()!='('){list.add(String.valueOf(stack.peek()));stack.pop();}}else{while(!stack.isEmpty()&&stack.peek()!='('){//。取出括号内部所有符号list.add(String.valueOf(stack.peek()));stack.pop();}stack.pop();}}else if (c == ' ') {//不处理}else {num=num+c;//拼接数字if(i+1>s.length()-1||s.charAt(i+1)=='+'||s.charAt(i+1)=='-'||s.charAt(i+1)=='('||s.charAt(i+1)==')'||s.charAt(i+1)==' '){//下一个不是数字,说明数字已经拼接完成list.add(num);//加入表达式num="";//清空numif(!stack.isEmpty()&&stack.peek()!='('){//将栈顶的符号加入表达式list.add(String.valueOf(stack.peek()));stack.pop();}}}}//这里以下就是逆波兰求值int a,b;for (int i = 0; i < list.size(); i++) {//从前向后遍历表达式if(list.get(i).equals("+")){//如果取出的时加法 a=nums.peek();nums.pop();b=nums.peek();nums.pop();nums.push(a+b);}else if(list.get(i).equals("-")){//如果取出的是减法a=nums.peek();nums.pop();if(nums.isEmpty()){//特殊处理-出现在表达式的第一个b=0;}else{b=nums.peek();nums.pop();}nums.push(b-a);}else{//如果出现的是数字,就压入数字栈中nums.push(Integer.parseInt(list.get(i)));}}return nums.peek();//结果就在数字栈的栈顶}
}

问题:代码阅读性差,并且时间复杂度比较高
在这里插入图片描述

题解思路厉害
括号展开 + 栈:具体思路就是展开所有的括号,由于只有±两个运算符号,它们拆开括号的效果如下,比如1+(1+2)=1+1+2;1-(1+2)=1-1-2,所以可以使用1和-1来表示加和减,具体做法如下

  1. 维护一个栈,初始将1压入栈,用来处理括号,(原因是默认后续符号不用翻转,此时规定了加为1,减为-1),创建ret保留最后结果,初始为0,设置一个sign初始为1,用来获取此时的符号
  2. 从前向后遍历字符串
  3. 如果出现’ ‘跳过不处理
  4. 如果出现+,获取栈顶的元素
  5. 如果出现-,获取栈顶元素*-1
  6. 如果出现括号(,就根据其前面的sign是1还是-1,将sign压入栈(此时如果sign为-1,就变成加为-1,减为1,原因在于出现了-()的情况)
  7. 如果出现括号),就弹出栈顶元素,此时就是恢复状态
  8. 如果出现为数字,就先向后找到所有数字,组合num,ret+=num*sign
  9. 最后返回ret
class Solution {public int calculate(String s) {Stack<Integer> kuo = new Stack<Integer>();//处理括号kuo.push(1);//初始设置为加为1 减为-1int sign = 1;//标记之前出现的符号int res = 0;//存放结果int i = 0;while (i < s.length()) {//遍历字符串if (s.charAt(i) == ' ') {//跳过i++;} else if (s.charAt(i) == '+') {//取出栈顶元素作为sign(如果此时为-(+),取出的sign=-1)sign = kuo.peek();i++;} else if (s.charAt(i) == '-') {//取出栈顶元素作为sign(如果此时为-(-),取出的sign=1)sign = kuo.peek()*-1;i++;} else if (s.charAt(i) == '(') {//根据sign即括号前的最后一个运算符,来决定括号内的加减法是1还是-1kuo.push(sign);i++;} else if (s.charAt(i) == ')') {//弹出之前括号内的环境,恢复为括号外的环境kuo.pop();i++;} else {long num = 0;while (i < s.length() && Character.isDigit(s.charAt(i))) {//找到所有数字字符拼接num = num * 10 + s.charAt(i) - '0';i++;}res += sign * num;//计算结果}}return res;}
}

相关文章:

  • 移动零--LeetCode
  • 切割PDF使用python,库PyPDF2
  • 区块链技术:深入共识算法、智能合约与DApps的架构奥秘
  • 【GIT】github中的仓库如何删除?
  • Langchain+RAG+向量数据库
  • vue-study(1)
  • java面向对象编程【基础篇】之基础语法
  • Day11(回溯法)——LeetCode79.单词搜索
  • 日语学习-日语知识点小记-构建基础-JLPT-N4阶段(10): つもり 计划/打算
  • Jenkins:开启高效软件开发的魔法之门
  • Java面试:从Spring Boot到微服务的全面考核
  • 【Leetcode 每日一题】2799. 统计完全子数组的数目
  • Nginx 中间件
  • 【一次成功!】Ubuntu22.04 安装 Autoware、 cuda、 cudnn、 TensorRT
  • PostgreSQL 分区表——范围分区SQL实践
  • Web3.0的认知补充(去中心化)
  • 从Kafka读取数据
  • “广州丰田汽车.网址”中文域名仲裁案:“网络门牌”保护战
  • Nginx 通过 Let‘s Encrypt 实现 HTTPS 访问全流程指南
  • 大模型是如何生成内容的?
  • 中美正在就关税问题谈判甚至会达成协议?外交部:都是假消息
  • 海关总署:明确部分货物、物品不再按进出境特殊物品监管
  • 解放军报社论:谱写新时代双拥工作崭新篇章
  • 秦洪看盘|平淡走势中或将孕育主旋律
  • 游客大理古城买瓜起争执:170克手机称出340克
  • 开发国内首个泌尿专科智能体,医生们将临床经验转变为知识图谱