Leetcode-224 基本计算器
题目:
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
示例 1:
输入:s = "1 + 1"
输出:2
示例 2:
输入:s = " 2-1 + 2 "
输出:3
示例 3:
输入:s = "(1+(4+5+2)-3)+(6+8)"
输出:23
提示:
1 <= s.length <= 3 * 105s由数字、'+'、'-'、'('、')'、和' '组成s表示一个有效的表达式- '+' 不能用作一元运算(例如, "+1" 和
"+(2 + 3)"无效) - '-' 可以用作一元运算(即 "-1" 和
"-(2 + 3)"是有效的) - 输入中不存在两个连续的操作符
- 每个数字和运行的计算将适合于一个有符号的 32位 整数
思路: 双栈法
使用双栈法,维护一个操作数栈和一个操作符栈,操作符栈可以放左括号,并且遇到右括号时先弹栈计算,直到弹出左括号。第一个操作符不计算,随后遇到一个操作符先将之前的操作符计算完后再压栈,并将计算结果压进操作数栈。最后再处理栈中剩余的元素,处理完成后操作数栈存放的就是计算结果。
注意:
- 设计一个计算函数,操作符和操作数弹栈操作都在此函数中进行。在弹栈过程中要注意判断栈中元素是否满足计算条件。压栈操作也在此函数中进行。
- 在进行计算时只需判断操作符栈的情况就行。
- 在遇到数字字符时,要把后面跟着的连续数字拼接起来作为完整的数字压栈。 - 新操作符入栈,先计算目前操作符栈内可计算的元素,要注意计算应当截至到遇到左括号或栈为空,因为只能先计算括号里面的元素。
- 初始时,要在操作数栈放一个0,防止第一个操作数是负数的情况。
- Java的字符串replaceAll函数返回一个新的改变后的字符串,需要赋值给原字符串才能完成原字符串的替换。
- 为防止 () 内出现的首个字符为运算符,将所有的空格去掉,并将 (- 替换为 (0-,(+ 替换为 (0+(当然也可以不进行这样的预处理,将这个处理逻辑放到循环里去做)
class Solution {
//使用双栈法,维护一个操作数栈和一个操作符栈,操作符栈可以放左括号,并且遇到右括号时先弹栈计算,直到弹出左括号。第一个操作符不计算,随后遇到一个操作符先将之前的操作符计算完后再压栈。最后再处理栈中剩余的元素。
public int calculate(String s) {
Stack<Integer> numStack = new Stack<>();
Stack<Character> opStack = new Stack<>();
//要在操作数栈中放一个0,避免出现第一个数字是负数的情况
numStack.push(0);
//字符串预处理空格,一元运算符,要注意给原字符串赋值
s = s.replaceAll(" ", "");
s = s.replaceAll("[(]-", "(0-");
//将字符串转换为字符数组
int n = s.length();
char[] cs = s.toCharArray();
for(int i = 0; i < n; ++i){
//如果是数字,则压入操作数栈,由于可能存在多位数字,因此需要遇到第一位数字时也把后面的数字也读入,作为完整的数字。
if(isNum(cs[i])){
String numString = "";
numString += cs[i];
++i;
while(i < n && isNum(cs[i])){
numString += cs[i];
++i;
}
int num = Integer.parseInt(numString);
numStack.push(num);
i--;
}
else if(cs[i] == '('){
opStack.push(cs[i]);
}
else if(cs[i] == '+' || cs[i] == '-'){
//新操作符入栈,先将栈内可计算的操作符计算了,直到遇到'('或操作符栈空,因为只能先计算括号里面的。
while(!opStack.isEmpty() && opStack.peek() != '('){
calculateCurrentNum(numStack, opStack);
}
opStack.push(cs[i]);
}
else if(cs[i] == ')'){
//要计算时只需要判断opStack栈就行了,毕竟有操作符才能计算
while(!opStack.isEmpty()){
if(opStack.peek() != '('){
calculateCurrentNum(numStack, opStack);
}
else{
opStack.pop();
break;
}
}
}
}
//最后要把剩下的操作符计算完
while(!opStack.isEmpty()){
calculateCurrentNum(numStack, opStack);
}
//计算完成后,numStack栈存放了计算结果
return numStack.peek();
}
private boolean isNum(char numChar){
return Character.isDigit(numChar);
}
//计算和结果压栈都在这个函数里进行,无需返回值
private void calculateCurrentNum(Stack<Integer> numStack, Stack<Character> opStack){
if(numStack.size() < 2 || numStack.isEmpty())
return;
if(opStack.isEmpty())
return;
int rightNum = numStack.pop();
int leftNum = numStack.pop();
char op = opStack.pop();
numStack.push((op == '+') ? leftNum+rightNum : leftNum-rightNum);
}
}
学到和回忆了:
- Java字符串相关用法
public String replaceAll(String regex, String replacement):替换字符串内的某个字符串,应当注意Java中的String类是不可变的,因此要把返回的新字符串赋值给原字符串才能做到替换的效果
public char[] toCharArray():将字符串转换为字符数组
public char charAt(int index):获取指定索引处的字符
public int length():获取字符串长度
public boolean isEmpty():判断字符串是否为空
public String concat(String s):将字符串s拼接在当前字符串后面
public int indexOf(int ch ):获取指定字符在字符串中出现的位置
public String substring(int beginIndex):获取当前字符串的子字符串
public String trim():删除字符串的头尾空白符
public boolean contains(CharSequence chars):判断当前字符串是否包含指定的字符或字符串
public String toLowerCase():将字符串转换为小写 - Java将字符串转为数字
static int parseInt(String s) - Java判断字符是否为数字
public static boolean isDigit(char ch)
浙公网安备 33010602011771号