【备战蓝桥杯】 算法·每日一题(详解+多解)-- day12

举报
苏州程序大白 发表于 2022/05/23 16:14:42 2022/05/23
【摘要】 @[TOC](【备战蓝桥杯】 算法·每日一题(详解+多解)-- day12) ✨博主介绍🌊 作者主页:苏州程序大白🌊 作者简介:🏆CSDN人工智能域优质创作者🥇,苏州市凯捷智能科技有限公司创始之一,目前合作公司富士康、歌尔等几家新能源公司💬如果文章对你有帮助,欢迎关注、点赞、收藏💅 有任何问题欢迎私信,看到会及时回复💅关注苏州程序大白,分享粉丝福利 计算器问题的双栈通用解法 题...

@[TOC](【备战蓝桥杯】 算法·每日一题(详解+多解)-- day12)

✨博主介绍

🌊 作者主页:苏州程序大白

🌊 作者简介:🏆CSDN人工智能域优质创作者🥇,苏州市凯捷智能科技有限公司创始之一,目前合作公司富士康、歌尔等几家新能源公司

💬如果文章对你有帮助,欢迎关注、点赞、收藏

💅 有任何问题欢迎私信,看到会及时回复
💅关注苏州程序大白,分享粉丝福利

计算器问题的双栈通用解法

题目

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

整数除法仅保留整数部分。

示例 1:
输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23

示例 2:
输入:s = “ 3+5 / 2 “
输出:5

注意:

这一类题有多种变式,如  `224 `. 基本计算器 中表达式只含有 `+`, ` - ``() ``227 `。
基本计算器  `II ` 中含有  `+ `,  `- `, *, ` / ``772 `. 基本计算器  `III ` 中含有 ` + `, `-, `  `* `,  `/ ` 以及  `() `。
介绍的双栈通用解法适用于以上所有题目。

解题思路

首先创建两个栈numsops,分别存放表达式中的数字和操作符。

然后从前往后遍历表达式,对于遍历到的字符做分类讨论。

空格:跳过

(:加入到 ops中,等待与之匹配的 )

):使用现有的 numsops进行计算,直到遇到左边最近的一个左括号为止,计算结果放回到nums

数字 : 从当前位置开始继续往后取,将整一个连续数字整体取出,加入 nums

运算符:加入到ops 中。在加入之前先把栈内可以算的都算掉(只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算),使用现有的 numsops进行计算,直到没有操作或者遇到左括号,计算结果放到nums

其中, 只有「栈内运算符」比「当前运算符」优先级高/同等,才进行运算 的意思是:假设当前已经扫描到了2 + 1(此时栈内的操作为+ )。

如果后面出现的+ 2或者- 1 的话,满足「栈内运算符」比「当前运算符」优先级高/同等,可以将 2 + 1算掉,把结果放到 nums 中;
如果后面出现的是* 2或者/ 1的话,不满足「栈内运算符」比「当前运算符」优先级高/同等,这时候不能计算 2 +

一些细节:

由于第一个数可能是负数,为了减少边界判断。一个小技巧是先往 nums添加一个0为防止()内出现的首个字符为运算符,将所有的空格去掉,并将 (- 替换为 (0-(+ 替换为(0+(当然也可以不进行这样的预处理,将这个处理逻辑放到循环里去做)。

class Solution {
  public int calculate(String s) {
    // 使用一个 Map 来维护运算符的优先级
    Map<Character, Integer> map = new HashMap<>();
    map.put('-', 1);
    map.put('+', 1);
    map.put('*', 2);
    map.put('/', 2);
    ArrayDeque<Integer> nums = new ArrayDeque<>();
    ArrayDeque<Character> ops = new ArrayDeque<>();
    // 防止第一个字符是负号,现在 nums 中添加一个 0
    nums.addLast(0);
    // 去掉所有空格
    s = s.replace(" ", "");
    char[] cs = s.toCharArray();
    for (int i = 0; i < cs.length; i++) {
      char c = cs[i];
      if (c == '(') {
        ops.addLast(c);
      } else if (c == ')') {
        // 运算 直到碰到与之对应的 (
        while (ops.peekLast() != '(') {
          calc(nums, ops);
        }
        // 运算完将 ( 弹出
        ops.pollLast();
      } else if (isNum(c)) {
        int sum = 0;
        int j = i;
        // 将数字整体取出
        while (j < cs.length && isNum(cs[j])) {
          sum = sum * 10 + (cs[j] - '0');
          j++;
        }
        nums.addLast(sum);
        // 遍历下标前移
        i = j - 1;
      } else {
        // 在特殊情况 (- 或 (+ 中加上 0
        if (i > 0 && cs[i - 1] == '(') {
          nums.addLast(0);
        }
        // 将运算符加入 ops 前先把能算的算完
        while (!ops.isEmpty() && ops.peekLast() != '(') {
          char prev = ops.peekLast();
          // 判断上一个运算符与当前的优先级关系
          if (map.get(prev) >= map.get(c)) {
            calc(nums, ops);
          } else {
            break;
          }
        }
        // 将运算符加入 ops
        ops.addLast(c);
      }
    }
    // 遍历结束 完成剩余运算
    while (!ops.isEmpty()) {
      calc(nums, ops);
    }
    return nums.peekLast();
  }


  void calc(ArrayDeque<Integer> nums, ArrayDeque<Character> ops) {
    // 数字数量小于 2 或运算符数量等于 0,不进行运算
    if (nums.size() < 2)
      return;
    if (ops.isEmpty())
      return;
    // 弹出两个数字
    int b = nums.pollLast();
    int a = nums.pollLast();
    // 弹出一个运算符
    char o = ops.pollLast();
    int c = 0;
    if (o == '-') {
      c = a - b;
    } else if (o == '+') {
      c = a + b;
    } else if (o == '*') {
      c = a * b;
    } else {
      c = a / b;
    }
    // 计算结果放回 nums
    nums.addLast(c);
  }

  boolean isNum(char c) {
    return Character.isDigit(c);
  }
}

💫点击直接资料领取💫

在这里插入图片描述

❤️关注苏州程序大白公众号❤️


👇 👇👇

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。