面试题 16.26. 计算器
采用Java实现。
方法一
维护两个栈,其中一个用来存储操作数,另外一个栈用来存储运算符。遍历字符串,如果是数字,那么直接入操作数栈,如果是操作符,就和运算符栈的栈顶元素比较:当运算符的优先级高于运算符栈的栈顶元素——直接入栈;否则取出运算符栈栈顶元素还有操作符栈栈顶两个元素,进行运算,将运算结果再入运算符栈;继续比较直到当前操作符入栈。
public class CalculatorByTwoStack {
private static final char ADD = '+';
private static final char SUBTRACT = '-';
private static final char MULTIPLY = '*';
private static final char DIVIDE = '/';
private static final char ZERO_CHAR = '0';
public int calculate(String s) {
Stack<Integer> operands = new Stack<>();
Stack<Character> operators = new Stack<>();
int num = 0;
for (int i = 0; i < s.length(); i++) {
char targetChar = s.charAt(i);
if (isNumber(targetChar)) {
num = 10 * num + targetChar - ZERO_CHAR;
}
if (isOperator(targetChar) || i == s.length() - 1) {
operands.push(num);
num = 0;
}
if (isOperator(targetChar)) {
calculateAndSaveOperator(operands, operators, targetChar);
}
}
while (!operators.isEmpty()) {
doOneOperator(operands, operators);
}
return operands.pop();
}
private void calculateAndSaveOperator(Stack<Integer> operands, Stack<Character> operators, char c) {
while (isOperatorPriorityLowerOrEqualThanTop(c, operators)) {
doOneOperator(operands, operators);
}
operators.push(c);
}
private void doOneOperator(Stack<Integer> operands, Stack<Character> operators) {
Integer topOperand = operands.pop();
Character operator = operators.pop();
Integer topNextedOperand = operands.pop();
if (operator == ADD) {
operands.push(topNextedOperand + topOperand);
} else if (operator == SUBTRACT) {
operands.push(topNextedOperand - topOperand);
} else if (operator == MULTIPLY) {
operands.push(topNextedOperand * topOperand);
} else {
operands.push(topNextedOperand / topOperand);
}
}
private boolean isOperatorPriorityLowerOrEqualThanTop(char c, Stack<Character> operators) {
if (operators.isEmpty()) {
return false;
}
Character topOperator = operators.peek();
return !isOperatorPriorityHigherThanTop(c, topOperator);
}
private boolean isOperatorPriorityHigherThanTop(char c, Character topOperator) {
return (topOperator == ADD || topOperator == SUBTRACT) && (c == MULTIPLY || c == DIVIDE);
}
private boolean isOperator(char c) {
return c == ADD || c == SUBTRACT || c == MULTIPLY || c == DIVIDE;
}
private boolean isNumber(char c) {
return c >= '0' && c <= '9';
}
}
方法二
维护一个栈,栈中的元素累加起来即是运算结果。默认上一个操作符为’+’,遍历字符串,如果是数字,那么暂时保存下来,向后继续遍历如果遇到操作符(或者字符串末尾),判断该数字的上一个操作符,如果为’+’,则直接将当前数字入栈,如果为’-’,则将当前数字取负数入栈,如果为’*’,将栈顶元素与当前数字相乘后入栈,如果为’/’,将栈顶元素与当前数字相除后入栈。最后将栈中元素进行累加即为运算结果
public class CalculatorByOneStack {
private static final char ADD = '+';
private static final char SUBTRACT = '-';
private static final char MULTIPLY = '*';
private static final char DIVIDE = '/';
private static final char ZERO_CHAR = '0';
public int calculate(String s) {
Stack<Integer> onlyAddedOperands = new Stack<>();
char operatorBeforeNumber = ADD;
int number = 0;
for (int i = 0; i < s.length(); i++) {
char currentChar = s.charAt(i);
if (isNumber(currentChar)) {
number = number * 10 + currentChar - ZERO_CHAR;
}
if (shouldDoCalculate(s, i, currentChar)) {
calculateAndSave(onlyAddedOperands, operatorBeforeNumber, number);
operatorBeforeNumber = currentChar;
number = 0;
}
// if currentChar = ' ' continue
}
return accumulateAllItems(onlyAddedOperands);
}
private boolean shouldDoCalculate(String s, int i, char currentChar) {
return isOperator(currentChar) || i == s.length() - 1;
}
private void calculateAndSave(Stack<Integer> onlyAddedOperands, char operatorBeforeNumber, int number) {
if (operatorBeforeNumber == ADD) {
onlyAddedOperands.push(number);
} else if (operatorBeforeNumber == SUBTRACT) {
onlyAddedOperands.push(-number);
} else if (operatorBeforeNumber == MULTIPLY) {
onlyAddedOperands.push(onlyAddedOperands.pop() * number);
} else {
onlyAddedOperands.push(onlyAddedOperands.pop() / number);
}
}
private int accumulateAllItems(Stack<Integer> stack) {
int result = 0;
while (!stack.isEmpty()) {
result += stack.pop();
}
return result;
}
private boolean isOperator(char c) {
return c == ADD || c == SUBTRACT || c == MULTIPLY || c == DIVIDE;
}
private boolean isNumber(char c) {
return c >= '0' && c <= '9';
}
}