美文网首页
LeetCode 基本计算器 II

LeetCode 基本计算器 II

作者: 吴敬悦 | 来源:发表于2021-03-11 23:52 被阅读0次

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

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

示例 1:

输入:s = "3+2*2"
输出:7

示例 2:

输入:s = " 3/2 "
输出:1

示例 3:

输入:s = " 3+5 / 2 "
输出:5

我的算法实现,目前还没有通过,显示超出时间限制:

class Solution {
    val digitsMap = mutableMapOf(
        Pair('0', 0), Pair('1', 1),
        Pair('2', 2), Pair('3', 3),
        Pair('4', 4), Pair('5', 5),
        Pair('6', 6), Pair('7', 7),
        Pair('8', 8), Pair('9', 9)
    )
    fun calc(a: Int, c: Char, b: Int):Int {
        return when(c) {
            '*' -> a * b
            '/' -> a / b
            '-' -> a - b
            else -> a + b
        }
    }
    fun getDigit(a: Int, s: String): IntArray {
        var sum = a
        var k = 1
        for (i in 1 until s.length) {
            if (digitsMap.contains(s[i])) {
                sum = sum*10 + digitsMap[s[i]]!!
                k ++
                continue
            }
            break
        }

        return intArrayOf(sum, k)
    }
    fun calculate(s: String): Int {

        if (digitsMap.contains(s[0])) {
            val dk = digitsMap[s[0]]?.let { getDigit(it, s) }
            if (dk?.get(1) == s.length) {
                return dk[0]
            }
        }

        val symbolMap = mutableMapOf(Pair('*', 2), Pair('/', 2), Pair('+', 1), Pair('-', 1))
        val symbol = Stack<Char>()
        val digits = Stack<Int>()
        var c: Char? = null
        var i = 0
        while (i < s.length) {
            if (digitsMap.contains(s[i])){
                val dk = digitsMap[s[i]]?.let { getDigit(it, s.slice(i until s.length)) }
                if (c != null) {
                    digits.push(dk?.get(0)?.let { calc(digits.pop(), c!!, it) })
                    c = null
                } else {
                    digits.push(dk?.get(0))
                }
                i += dk?.get(1)!!
            } else if (symbolMap.contains(s[i])) {
                if (symbol.size > 0) {
                    val char = symbol.pop()

                    if (symbolMap[char]!! < symbolMap[s[i]]!!) {
                        c = s[i]
                        symbol.push(char)
                    } else {
                        c = null
                        val a = digits.pop()
                        val b = digits.pop()
                        digits.push(calc(b, char, a))
                        symbol.push(s[i])
                    }
                } else {
                    symbol.push(s[i])
                }
                i++
            }
        }
        val a = digits.pop()
        val b = digits.pop()
        return calc(b, symbol.pop(), a)
    }
}

明天继续,最先开始想的就是先实现出来,然后再优化。

补充,我觉得我实现的并没有什么问题,但是使用 kotlin 就是出现了问题,于是我使用 javascript 实现了一遍,发现居然通过了,虽然耗时也不低:

      // 将字符串转换成数组表达式
      const getExpressionArr = (s) => {
        let dStr = "";
        const arr = [];
        for (let i = 0; i < s.length; i++) {
          // 如果是空字符串则跳过
          if (s[i] === " ") continue;
          // 如果是数字,那么就累加数组
          if (!isNaN(parseInt(s[i], 10))) {
            dStr += s[i];
            continue;
          }
          // 当遇到非数组以及空格之外的符号则添加到数组中
          arr.push(dStr - 0, s[i]);
          dStr = "";
        }
        arr.push(dStr - 0)
        return arr;
      };
      // 计算
      const calc = (a, c, b) => {
        switch (c) {
          case "-":
            return a - b;
          case "*":
            return a * b;
          case "/":
            return Math.floor(a / b);
          default:
            return a + b;
        }
      };
      /**
       * @param {string} s
       * @return {number}
       */
      var calculate = function (s) {
        const swapArr = getExpressionArr(s);
        const symbolGrade = {"-": 1, "+": 1, "*":2, "/": 2}
        const digits = [],
          symbols = [];
        // 保存字符,就是那个大于前面字符的字符
        let c = null;
        for (let i = 0; i < swapArr.length; i++) {
          // 当值是数字的时候
          if (typeof swapArr[i] === "number") {
            if (c !== null) {
              // 根据条件大的字符将新的计算结果保存起来
              digits.push(calc(digits.pop(), c, swapArr[i]));
              // 操作完成以后置为 null
              c = null;
            } else {
              digits.push(swapArr[i]);
            }
          } else {
            if (symbols.length > 0) {
              const char = symbols.pop()
              // 当当前的字符等级大于前面的字符等级,那么把最新的字符保存起来
              if (symbolGrade[char] < symbolGrade[swapArr[i]]) {
                c = swapArr[i]
                symbols.push(char)
              } else {
                // 如果字符等级相同,那么先计算前面的结果
                const b = digits.pop();
                const a = digits.pop();
                digits.push(calc(a, char, b))
                symbols.push(swapArr[i])
              }
            } else {
              symbols.push(swapArr[i])
            }
          }
        }
        const b = digits.pop();
        const a = digits.pop() || 0;
        return calc(a, symbols.pop(), b)
      };

为啥 kotlin 这么慢呢,看了一圈并没有发现原因,真的很奇怪,慢得一批。

提示:

  • 1 <= s.length <= 3 * 105
  • s 由整数和算符 ('+', '-', '*', '/') 组成,中间由一些空格隔开
  • s 表示一个 有效表达式
  • 表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1] 内
  • 题目数据保证答案是一个 32-bit 整数

来源:力扣(LeetCode)

相关文章

网友评论

      本文标题:LeetCode 基本计算器 II

      本文链接:https://www.haomeiwen.com/subject/ssdaqltx.html