1、计算器问题
题目:LeetCode227
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。
示例:
输入:s = “3+2*2”
输出:7
方法:遍历字符串s,并用变量preSign记录每个数字之前的运算符,每次遍历到数字末尾时,根据该数字之前的运算符preSign来决定计算方式。preSign初始值设为加号:
加号:将数字压入栈;
减号:将数字的相反数压入栈;
乘除号:计算数字与栈顶元素,并将栈顶元素替换为计算结果;
代码实现中,若读到一个运算符,或者遍历到字符串末尾,即认为是遍历到了数字末尾。处理完该数字后,更新preSign为当前遍历的字符。
遍历完字符串s后,将栈中元素累加,即为该字符串表达式的值。
Java代码:
public int calculate(String s) {
Deque<Integer> stack = new ArrayDeque<Integer>();
char perSign = '+';
int num = 0;
int n = s.length();
for(int i = 0; i < n; i ++){
if(Character.isDigit(s.charAt(i))){
num = num * 10 + s.charAt(i) - '0';
}
if( !Character.isDigit(s.charAt(i)) && s.charAt(i) != ' ' || i == n - 1){
switch(perSign){
case '+':
stack.push(num);
break;
case '-':
stack.push(-num);
break;
case '*':
stack.push(stack.pop() * num);
break;
default:
stack.push(stack.pop() / num);
}
perSign = s.charAt(i);
num = 0;
}
}
int ans = 0;
while( !stack.isEmpty() ){
ans += stack.pop();
}
return ans;
}
Python代码:
def calculate(self, s):
n = len(s)
stack = []
preSign = '+'
num = 0
for i in range(n):
if s[i] != ' ' and s[i].isdigit():
num = num * 10 + ord(s[i]) - ord('0')
if i == n - 1 or s[i] in '+-*/':
if preSign == '+':
stack.append(num)
elif preSign == '-':
stack.append(-num)
elif preSign == '*':
stack.append(stack.pop() * num)
else:
#原来python没有自动转成int型数字的功能,必须额外写上
#我宣布python是最怪的语言,负数取正竟然是向下取整,别的语言不用int型就能直接向上取整
t = stack.pop()
if t < 0 and t % num != 0 :
stack.append(int(t / num) + 1)
else:
stack.append(int(t / num))
preSign = s[i]
num = 0
return sum(stack)
C++代码:
public:
int calculate(string s) {
stack<int> numStack;
int num = 0;
char sign = '+';
for(int i = 0; i < s.length(); i ++){
char c = s[i];
if(isdigit(c)){
num = num * 10 + (c - '0');
}
if( !isdigit(c) && c != ' ' || i == s.length() - 1){
if(sign == '+'){
numStack.push(num);
}
else if(sign == '-'){
numStack.push(-num);
}
else if(sign == '*'){
//java这样写就行,C++就不行,哎说是'void' and 'int'
//numStack.push(numStack.pop() * num);
int prevNum = numStack.top();
numStack.pop();
numStack.push(prevNum * num);
}
else if(sign == '/'){
int prevNum = numStack.top();
numStack.pop();
numStack.push(prevNum / num);
}
sign = c;
num = 0;
}
}
int result = 0;
while(!numStack.empty()){
result += numStack.top();
numStack.pop();
}
return result;
}
2、逆波兰表达式
题目:LeetCode150
给你一个字符串数组 tokens,表示一个根据逆波兰表示法表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
示例:
输入:tokens = [“2”,“1”,“+”,“3”,“*”]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
基础认识:将一般表达式转化成二叉树,使用的是中序遍历。
例如:中缀表达式:1 + (2 + 3) * 4 - 5转化成二叉树为
根据这个二叉树:
前缀表达式为:- + 1 * + 2 3 4 5
后缀表达式为:1 2 3 + 4 * + 5 -
但对于计算机来说,中缀表达式是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转化成前缀或后缀表达式再进行求解。
前缀表达式的运算符位于两个相应操作数之前,前缀表达式又被称为前缀记法或波兰式。
后缀表达式与其相反,即逆波兰式。
方法:利用栈,遇见数字即进栈,遇见运算符,则取出栈中最上面的两个元素进行计算,最后将运算结果入栈。
Java代码:
public int evalRPN(String[] tokens) {
Stack<Integer> stack = new Stack<>();
//token是字符串
for(String token : tokens){
if(!Character.isDigit(token.charAt(0)) && token.length() == 1){
//运算符,从栈中取出两个数进行运算
int b = stack.pop();
int a = stack.pop();
switch(token){
//根据运算符的种类进行计算,将结果直接入栈
case "+": stack.push(a + b); break;
case "-": stack.push(a - b); break;
case "*": stack.push(a * b); break;
case "/": stack.push(a / b); break;
}
}
else{
//整数直接入栈
stack.push(Integer.parseInt(token));
}
}
return stack.pop();
}
Python代码:
def evalRPN(self, tokens):
stack = [];
for token in tokens:
#运算符,从栈中取出两个树进行运算
if len(token) == 1 and not token.isdigit():
b = stack.pop()
a = stack.pop()
if token == '+':
stack.append(a + b)
elif token == '-':
stack.append(a - b)
elif token == '*':
stack.append(a * b)
elif token == '/':
if a % b != 0 and a / b < 0:
stack.append(int(a / b) + 1)
else:
stack.append(int(a / b))
else:
#整数直接入栈
stack.append(int(token))
return stack.pop()
C语言代码:
int evalRPN(char** tokens, int tokensSize) {
int stack[tokensSize];
int top = -1;
for(int i = 0; i < tokensSize; i ++){
//token应该也是一种数组或字符串
char* token = tokens[i];
if(strlen(token) == 1 && !isdigit(token[0])){
//运算符,从栈中取出两个数经行计算
int b = stack[top --];
int a = stack[top --];
switch(token[0]){
//根据运算符的种类进行计算,将结果直接入栈
case '+':
stack[++ top] = a + b;
break;
case '-':
stack[++ top] = a - b;
break;
case '*':
stack[++ top] = a * b;
break;
case '/':
stack[++ top] = a / b;
break;
}
}
else{
//整数直接入栈,atoi是类型转换符吗?
stack[++ top] = atoi(token);
}
}
return stack[top];
}
Python代码(本地编辑器测试代码):
class EvalRPN():
def evalRPN(self, tokens):
stack = [];
for token in tokens:
#运算符,从栈中取出两个树进行运算
if len(token) == 1 and not token.isdigit():
b = stack.pop()
a = stack.pop()
if token == '+':
stack.append(a + b)
elif token == '-':
stack.append(a - b)
elif token == '*':
stack.append(a * b)
elif token == '/':
stack.append(int(a / b))
"""
这个地方的话是有歧义的,不同版本python规则不一样
if a % b != 0 and a / b < 0:
stack.append(int(a / b) + 1)
else:
stack.append(int(a / b))
"""
else:
#整数直接入栈
stack.append(int(token))
return stack.pop()
#以下是测试代码:
if __name__ == '__main__':
tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
solution = EvalRPN()
result = solution.evalRPN(tokens)
print("The result is:",result)
本篇文章为原创文,欢迎转载,请注明文章出处https://blog.csdn.net/2301_79084755/article/details/136426642。技术类文章一般都有时效性,本人会不定期对自己的博客进行修正更新,因此请访问出处以查看本文的最新版本。