今天在刷leet code的时候刷到了一道题,后缀表达式(逆波兰表达式)求值,我花了一会儿写了一下它的解法。但是今天我不谈什么是后缀表达式,有兴趣的同学可以去论坛上看看其他人聊后缀表达式的问题,单就解题来说,我用了最为常规的办法,应该也是初学者最容易理解的方法写的,故代码数量较多,一定要读下去哦!
首先我们拿出一个后缀表达式的例子,这里我直接用力扣上的测试用例。
String[] expression = {"2", "1", "+", "3", "*"};
//其转化为中缀表达式就是 ((2 + 1) * 3) = 9
对于后缀表达式求值,我们有这样一个规则:
1. ==遇到数字则入栈。==
2. ==遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。==
我相信有很多同学会有疑惑为什么直接接给出了这个规则,怎么来的这个规则,其实我也会有这样的疑惑,但是我觉得有可能是因为计算机的工作原理,栈的工作原理所知,以前的程序员可能就总结出了很多规律供我们使用。实际上我们不用事事都去追根溯源,要学会使用工具和思考,该深思的地方才去深思,避免重复造轮子。
通过理解规则我们首先能想到的是,这个题我们应该要用到栈(Stack),所以我尝试用图的方式来演示该工作过程。
第一步:
{“2”, “1”, “+”, “3”, “*”}
首先遍历的是第一个元素 “2”,此时是数字,直接入栈。
第二步:
{“2”, “1”, “+”, “3”, “*”}
第三步:
{“2”, “1”, “+”, “3”, “*”}
继续遍历下一个元素 “+”,此时我们遇到了规则里面的第二个条件,不是数字了,我们将从栈中弹出两个数字,进行运算,也就是==1 和 2==进行1+2=3,并将3入栈。
第四步:
{“2”, “1”, “+”, “3”, “*”}
遍历到第四个元素 “3”,直接入栈。
第五步:
{“2”, “1”, “+”, “3”, “*”}
遍历最后一个元素 “*”,此时又要从栈里面弹出两个数字,进行运算,也就是3*3=9,再将9入栈。
当遍历完链表中所有元素时,栈中的唯一的一个数字即为最终的运算结果。
接下来,我们准备进行代码实现。
我们首先定义一个方法对弹出来的数字进行运算。
值得注意的是,在后缀表达式求值时,从栈中弹出来的数,越靠近栈底的数,就要作为被减数,被除数
代码如下:
/**
* 该方法用于计算
*/
public static int cal(int num1,int num2,String oper){
int result = 0;
switch (oper){
case "+":
result = num1 + num2;
break;
case "-":
result = num2 - num1; //靠近栈底的做被减数
break;
case "*":
result = num1 * num2;
break;
case "/":
result = num2 / num1; //靠近栈底的做被除数
break;
default:
break;
}
return result;
}
然后还需要定义一个用于遍历字符数组,完成入栈弹栈操作的方法
代码如下:
public static int calculate(List<String> ls){
Stack<String> stack = new Stack<>();
for (String l : ls) {
if (l.matches("-?\\d+")){//正则表达式匹配数字
stack.push(l);
}else{
String num1 = stack.pop();
String num2 = stack.pop();
int calculate = cal(Integer.parseInt(num1), Integer.parseInt(num2), l);
stack.push(String.valueOf(calculate));
}
}
return Integer.parseInt(stack.pop());
}
在对数字进行判别的时候我采用了正则表达式,并考虑到可能为多位数,负数的情况,不理解的同学可以去了解一下正则表达式。
最后就是测试了:
@Test
public void test() {
//定义一个逆波兰表达式
String[] surffixExpression = {"2", "1", "+", "3", "*"};
int result = calculate(surffixExpression);
System.out.println(result);
}
至此,后缀表达式的求值就完成了,此方法我认为是初学者最容易理解的方法,不懂的同学可以多画图去理解,一边画图一边思考,算法题画图还是很重要的,动起来,一起学习。