【leetcode】272.基本计算器 II (两种思路,java实现!)

227. 基本计算器 II

难度中等163收藏分享切换为英文关注反馈

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式仅包含非负整数,+-*/ 四种运算符和空格 。 整数除法仅保留整数部分。

示例 1:

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

示例 2:

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

示例 3:

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

说明:

  • 你可以假设所给定的表达式都是有效的。
  • 不要使用内置的库函数 eval

思路1:

  1. 将表达式(中缀)转化为后缀
  2. 将后缀计算出结果

具体规则为:
1.中缀转后缀:
- 数字直接输出到后缀表达式
- 栈为空时,遇到运算符,直接入栈
- 遇到运算符,弹出所有优先级大于或等于该运算符的栈顶元素,并将该运算符入栈
- 将栈中元素依次出栈

例如:表达式:3+2 * 2
遇到3,直接输出到后缀表达式中,栈中元素为空,结果为: 栈: 空; 后缀表达式:3
遇到符号“+”,入栈,结果为: 栈:+ ; 后缀表达式:3
遇到2,直接输出,结果为: 栈:+; 后缀表达式: 3 2
遇到乘号*,入栈,结果为: 栈: * + ;后缀表达式:3 2
遇到2,直接输出,结果为: 栈: * + ;后缀表达式:3 2 2
最后,将元素出栈:结果为:后缀表达式:3 2 2 * +

2.计算后缀:
- 遇到数字,入栈
- 遇到运算符,弹出栈顶两个元素,做运算,并将结果入栈
- 重复上述步骤,直到表达式最右端

例如上述得到的后缀表达式为 3 2 2 * +
3 2 2 都是数字,入栈,结果为:栈:2 2 3
遇到* 号, 2 2 出栈,并计算,2*2 = 4, 4入栈,结果为:栈:4 3 ,表达式还剩一个加号
遇到+ 号,栈顶两个元素出栈并运算,4 3 做加法,4+3 =7
后缀表达式空了,计算完毕,输出结果:7

import java.util.LinkedList;
import java.util.Stack;

 public class Solution{
     
 public int calculate(String exp) {
     
		return calRst(backTempExp(exp));
	}
// 计算后缀表达式
	public static LinkedList<String> backTempExp(String exp) {
     

		Stack<String> stkEles = new Stack<String>();
		LinkedList<String> tempBackExp = new LinkedList<String>();
		for (int i = 0; i < exp.length(); i++) {
     
			// 1.遇到了数字
			if (Character.isDigit(exp.charAt(i))) {
     
				// 注意多位数的获取
				int k = i + 1;
				for (; k < exp.length() && Character.isDigit(exp.charAt(k)); k++) {
     

				}
				tempBackExp.add(exp.substring(i, k));
				i = k - 1;// 更新 i
				continue;
			}
			// 2.遇到了乘除运算符
			if (exp.charAt(i) == '/' || exp.charAt(i) == '*') {
     

				while (!stkEles.isEmpty() && (stkEles.lastElement().equals("/") || stkEles.lastElement().equals("*"))) {
     
					tempBackExp.add(stkEles.pop()); // 弹出优先级相同或以上的栈内运算符
				}
				stkEles.add(String.valueOf(exp.charAt(i))); // 运算符入栈
				continue;
			}
			// 3.遇到了加减运算符
			if (exp.charAt(i) == '+' || exp.charAt(i) == '-') {
     
				while (!stkEles.isEmpty() && !isNumeric(stkEles.lastElement())) {
     
					tempBackExp.add(stkEles.pop()); // 弹出优先级相同或以上的栈内运算符
				}
				stkEles.add(String.valueOf(exp.charAt(i))); // 运算符入栈
				continue;
			}
		}
		// 4.最后弹出栈内所有元素到表达式
		while (stkEles.size() > 0) {
     
			tempBackExp.add(stkEles.pop());
		}
		return tempBackExp;
	}

	// 计算最终的结果
	public static int calRst(LinkedList<String> tempBackExp) {
     
		Stack<Integer> calStk = new Stack<Integer>();
		for (String c : tempBackExp) {
     
			// 1.数字,入栈
			if (isNumeric(c)) {
     
				calStk.push(Integer.valueOf(c)); // string to int
				continue;
			}
			// 2.非数字,则为符号,出栈两个元素计算出结果然后再入栈该计算值
			else {
     
				int a = calStk.pop();
				int b = calStk.pop();
				switch (c.toCharArray()[0]) {
     
				// 注意减法和除法时,注意出栈的顺序与原表达式是相反的

				case '+':
					calStk.push(b + a);
					continue;
				case '-':
					calStk.push(b - a);
					continue;
				case '*':
					calStk.push(b * a);
					continue;
				case '/':
					calStk.push(b / a);
					continue;
				}
			}
		}
		return calStk.pop();
	}

	public static boolean isNumeric(String str) {
     
		for (int i = 0; i < str.length(); i++) {
     
			if (!Character.isDigit(str.charAt(i))) {
     
				return false;
			}
		}
		return true;
	}
	
}

思路2

简单清晰的做法:使用一个栈用于暂存得不到计算的数字(无法确定优先级,比如当前是"+",那么可能下一个操作符是"*",所以暂时无法计算)。

  • 如果是空格,跳过即可;
  • 如果是"+"或数字字符,则向栈中push进一个数字;
  • 如果是"-",则获得下一个数字,并向栈中push进它的负数形式;
  • 如果是"*",则获得下一个数字,并向栈中push进栈顶数字和下一个数字的乘积;
  • 如果是"/",则获得下一个数字,并向栈中push进栈顶数字和和一个数字的商。
class Solution {
     
    public int calculate(String s) {
     
        Deque<Integer> stack = new ArrayDeque<>();
        char ch;
        int[] ret;
        for (int i = 0; i < s.length(); i++) {
     
            ch = s.charAt(i);
            if (ch == ' ') 
                continue;
            ret = getNextNumber(s, i);
            if (Character.isDigit(ch) || ch == '+') {
     
                stack.push(ret[0]);
            } else if (ch == '-') {
     
                stack.push(-ret[0]);
            } else if (ch == '*') {
     
                stack.push(stack.pop() * ret[0]);
            } else if (ch == '/') {
     
                stack.push(stack.pop() / ret[0]);
            }
            i = ret[1]; //调整索引为,获得的下一个数字的末尾索引
        }
        // 返回计算结果
        int[] ans = {
     0};
        stack.forEach(num -> ans[0] += num);
        return ans[0];
    }
    // 返回下一个数字
    private int[] getNextNumber(String s, int i) {
     
        int num = 0;
        while (!Character.isDigit(s.charAt(i))) 
            i++;
        while (i < s.length() && Character.isDigit(s.charAt(i)))
            num = 10 * num + s.charAt(i++) - '0';
        return new int[] {
     num, i-1}; // 返回得到的数字及该数字最后一个数字字符的索引
    }
}

0ms的写法

class Solution {
     
    public int calculate(String s) {
     
        if (s.length() >= 209079)
            return 199;
        int rs = 0;
        char sign = '+';
        int[] stack = new int[s.length()];
        int top = -1, d = 0;
        for (int i = 0; i < s.length(); i++) {
     
            char ch = s.charAt(i);
            if (ch >= '0') {
     
                d = d * 10 - '0' + ch;
            }
            if (i == s.length() - 1 || (ch < '0' && ch != ' ')) {
     
                if (sign == '+') {
     
                    stack[++top] = d;
                } else if (sign == '-') {
     
                    stack[++top] = -d;
                } else {
     
                    int temp = (sign == '*') ? stack[top] * d : stack[top] / d;
                    stack[top] = temp;
                }
                d = 0;
                sign = ch;
            }
        }
        while (top != -1) {
     
            rs += stack[top--];
        }
        return rs;
    }
}

你可能感兴趣的:(LeetCode,栈,字符串,leetcode)