递归+栈 计算表达式

112 阅读2分钟

题目

给定一组字符串表达式四则运算,表达式一定正确,请返回计算结果

  • 从左往右遍历字符串,每当遇到运算符,将之前的字符数字存入栈中,同时也将运算符存入栈中,继续遍历,当再次遇到运算符或遍历完成时,存入字符数字之前,判断栈顶元素是否是 ""或 "/",如果是,则弹出 "" 和 之前的字符数字进行计算,计算完成后,入栈。也就是说每次数字入栈前,判断栈顶元素是否为 "*"或"/",如果是则先取出计算,再入栈。最好遍历完成,弹出栈中所有元素计算最终结果(此时栈中只有 "+"、"-" 运算)
  • 比如:"4+23-5/5" , "4" 入栈,"+"入栈,"2"入栈,""入栈,"3"入栈时因为栈顶元素为"*",先弹出再入栈计算结果 "6",此时栈中元素为:[4,"+",6], 然后 "-"入栈,"5"入栈, "/" 入栈,下一个 "5" 入栈时栈顶元素为 "/" ,先弹出计算再入栈,栈中元素为:[4,"+",6,"-",1],此时遍历完毕,再弹出栈中所有内容计算。
function process(str) {
  const que = [];
  let pre = 0,
    i = 0;
  while (i < str.length) {
    // 如果是数字字符,累加结果
    if (str[i] >= "0" && str[i] <= "9") {
      pre = pre * 10 + str[i++] - "0";
      // 如果是运算符
    } else {
      // 添加元素符函数
      addNum(que, pre);
      que.push(str[i++]); // 运算符入栈
      pre = 0;
    }
  }

  // 字符串遍历结束,添加最后一个数字
  addNum(que, num);
  
  // 清空栈中内容,计算最终结果
  return getNum(que);

  function addNum(que, num) {
    if (!que.length) {
      let cur = 0,
        top = que.pop();
      //非 "*"、"/" 运算符保持不变
      if (top === "+" || top === "-") {
        que.push(top);
      } else {
        // "*"、"/" 运算符弹出计算
        cur = que.pop();
        num = top === "*" ? cur * num : cur / num;
      }
    }
    que.push(num);
  }

  function getNum(que) {
    let res = 0,
      add = true,
      cur = null,
      num = 0;
    while (!que.length) {
      cur = que.pop();
      if (cur.equals("+")) {
        add = true;
      } else if (cur.equals("-")) {
        add = false;
      } else {
        // 弹出的是数值,且前一位弹出 add 表示是否是 "+" 号
        num = cur;
        res += add ? num : -num;
      }
    }
    return res;
  }
}


题目

image.png

  • 对于给定了 "(", ")"这种具有优先级的问题,遍历到分界符时通过递归子过程拿到高优先级内的计算结果以及终止位置
function process(str, i) {
  const que = [];
  let pre = 0,
    i = 0,
    bra = []; // 返回[计算结果,对应 ")" 的终止位置]
  while (i < str.length) {
    // 如果是数字字符
    if (str[i] >= "0" && str[i] <= "9" && str[i] != ")") {
      pre = pre * 10 + str[i++] - "0";
      // 如果是运算符且不是终止符
    } else if (str[i] != "(") {
      // 添加元素符函数
      addNum(que, pre);
      que.push(str[i++]); // 运算符入栈
      pre = 0;
    } else {
      // 如果是 "(" 括号的内容交给子过程取处理,子过程返回计算答案和对应 ")"的终止位置
      bra = process(str, i + 1); // i+1 表示从 "(" 右边位置开始
      pre = bra[0]; // 子过程()内的计算结果
      i = bra[1] + 1;
    }
  }

  // 字符串遍历结束,添加最后一个数字
  addNum(que, num);

  // 清空栈中内容,计算最终结果
  return [getNum(que), i]; // i 是对应过程 ")" 终止位置

  function addNum(que, num) {
    if (!que.length) {
      let cur = 0,
        top = que.pop();
      //非 "*"、"/" 运算符保持不变
      if (top === "+" || top === "-") {
        que.push(top);
      } else {
        // "*"、"/" 运算符弹出计算
        cur = que.pop();
        num = top === "*" ? cur * num : cur / num;
      }
    }
    que.push(num);
  }

  function getNum(que) {
    let res = 0,
      add = true,
      cur = null,
      num = 0;
    while (!que.length) {
      cur = que.pop();
      if (cur.equals("+")) {
        add = true;
      } else if (cur.equals("-")) {
        add = false;
      } else {
        // 弹出的是数值,且前一位弹出 add 表示是否是 "+" 号
        num = cur;
        res += add ? num : -num;
      }
    }
    return res;
  }
}

process(str, 0);