表达式解题套路学习之旅

163 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

给定一个字符串str,str表示一个公式,公式里可能有整数、加减乘除符号和左右括号,返回公式的计算结果,难点在于括号可能嵌套很多层

  1. str="48*((70-65)-43)+8*1",返回-1816。
  2. str="3+1*4",返回7。
  3. `str="3+(1*4)",返回7。

一、说明

  1. 可以认为给定的字符串一定是正确的公式,即不需要对str做公式有效性检查
  2. 如果是负数,就需要用括号括起来,比如“4*(-3)”但如果负数作为公式的开头或括号部分的开头,则可以没有括号,比如"-3*4""(-3*4)"都是合法的。
  3. 不用考虑计算过程中会发生溢出的情况。

二、实现

34 + 1 * 2 + 4/3 + 7

如果表达式中没有小括号怎么算?

当前指针指向数字或符号,这两种情况

int cur = 0

如果表达式中有小括号怎么算?

定义函数f(str, int i) ,返回int[2],str[i...] i到遇到 ) 或 字符串终止位置

  1. ans 负责这段的结果(终止位置的结果)
  2. i 算到哪个位置停的(终止位置 ')' 或 结束)
  3. 遇到左括号就交给递归搞(遇到左括号就掉下一个f函数),我才不管呢!由下一个函数返回结果

"1 + 2 * (3 + 4 * (2 - 1)) + 5"

"23 * ((5 + 2) * (3 - 4))"

三、图解

image.png

四、实现

代码如下:

	public static int calculate(String str) {
		return f(str.toCharArray(), 0)[0];
	}

	// 请从str[i...]往下算,遇到字符串终止位置或者右括号,就停止
	// 返回两个值,长度为2的数组
	// 0) 负责的这一段的结果是多少
	// 1) 负责的这一段计算到了哪个位置
	public static int[] f(char[] str, int i) {
		LinkedList<String> que = new LinkedList<String>();
		int cur = 0;
		int[] bra = null;
		// 从i出发,开始撸串
		while (i < str.length && str[i] != ')') {
			if (str[i] >= '0' && str[i] <= '9') {
				cur = cur * 10 + str[i++] - '0';
			} else if (str[i] != '(') { // 遇到的是运算符号
				addNum(que, cur);
				que.addLast(String.valueOf(str[i++]));
				cur = 0;
			} else { // 遇到左括号了
				bra = f(str, i + 1);
				cur = bra[0];
				i = bra[1] + 1;
			}
		}
		addNum(que, cur);
		return new int[] { getNum(que), i };
	}

	public static void addNum(LinkedList<String> que, int num) {
		if (!que.isEmpty()) {
			int cur = 0;
			String top = que.pollLast();
			if (top.equals("+") || top.equals("-")) {
				que.addLast(top);
			} else {
				cur = Integer.valueOf(que.pollLast());
				num = top.equals("*") ? (cur * num) : (cur / num);
			}
		}
		que.addLast(String.valueOf(num));
	}

	public static int getNum(LinkedList<String> que) {
		int res = 0;
		boolean add = true;
		String cur = null;
		int num = 0;
		while (!que.isEmpty()) {
			cur = que.pollFirst();
			if (cur.equals("+")) {
				add = true;
			} else if (cur.equals("-")) {
				add = false;
			} else {
				num = Integer.valueOf(cur);
				res += add ? num : (-num);
			}
		}
		return res;
	}

LeetCode

五、总结

类似的题:公式、元素(化学)、压缩(aaa => 3{a})

处理括号嵌套题的套路:

  1. 请从str[i...]往下算,遇到字符串终止位置或者右括号,就停止
  2. 返回两个值,长度为2的数组
    1. arr[0] 负责的这一段的结果是多少
    2. arr[1] 负责的这一段计算到了哪个位置