题目

标题和出处

标题:逆波兰表达式求值

出处:150. 逆波兰表达式求值

难度

4 级

题目描述

要求

根据逆波兰表示法,求表达式的值。

有效的算符包括 栈题目:逆波兰表达式求值 - 图1栈题目:逆波兰表达式求值 - 图2栈题目:逆波兰表达式求值 - 图3栈题目:逆波兰表达式求值 - 图4。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

注意整数除法向零取整。

给定的逆波兰表达式总是有效的。表达式总会得出有效数值且不存在除数为 栈题目:逆波兰表达式求值 - 图5 的情况。

示例

示例 1:

输入:栈题目:逆波兰表达式求值 - 图6
输出:栈题目:逆波兰表达式求值 - 图7
解释:栈题目:逆波兰表达式求值 - 图8%20*%203)%20%3D%209%7D#card=math&code=%5Ctexttt%7B%28%282%20%2B%201%29%20%2A%203%29%20%3D%209%7D&id=XBLEO)

示例 2:

输入:栈题目:逆波兰表达式求值 - 图9
输出:栈题目:逆波兰表达式求值 - 图10
解释:栈题目:逆波兰表达式求值 - 图11)%20%3D%206%7D#card=math&code=%5Ctexttt%7B%284%20%2B%20%2813%20%2F%205%29%29%20%3D%206%7D&id=qBido)

示例 3:

输入:栈题目:逆波兰表达式求值 - 图12
输出:栈题目:逆波兰表达式求值 - 图13
解释:

栈题目:逆波兰表达式求值 - 图14%20%20-11)))%20%2B%2017)%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20((10%20%20(6%20%2F%20(12%20%20-11)))%20%2B%2017)%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20((10%20%20(6%20%2F%20-132))%20%2B%2017)%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20((10%20*%200)%20%2B%2017)%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20(0%20%2B%2017)%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%2017%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%2022%7D%0A%5Cend%7Baligned%7D%0A#card=math&code=%5Cbegin%7Baligned%7D%0A%26%20%5Cquad%20%5Ctexttt%7B%28%2810%20%2A%20%286%20%2F%20%28%289%20%2B%203%29%20%2A%20-11%29%29%29%20%2B%2017%29%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20%28%2810%20%2A%20%286%20%2F%20%2812%20%2A%20-11%29%29%29%20%2B%2017%29%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20%28%2810%20%2A%20%286%20%2F%20-132%29%29%20%2B%2017%29%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20%28%2810%20%2A%200%29%20%2B%2017%29%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%20%280%20%2B%2017%29%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%2017%20%2B%205%7D%20%5C%5C%0A%26%20%5Ctexttt%7B%3D%2022%7D%0A%5Cend%7Baligned%7D%0A&id=LwTdf)

数据范围

  • 栈题目:逆波兰表达式求值 - 图15
  • 栈题目:逆波兰表达式求值 - 图16 或者是一个算符(栈题目:逆波兰表达式求值 - 图17栈题目:逆波兰表达式求值 - 图18栈题目:逆波兰表达式求值 - 图19栈题目:逆波兰表达式求值 - 图20),或者是一个在范围 栈题目:逆波兰表达式求值 - 图21 内的整数

解法一

思路和算法

逆波兰表达式又称后缀表达式,由波兰的逻辑学家 J・卢卡西维兹于 1929 年提出。逆波兰表达式的特点是:没有括号,运算符总是放在和它相关的操作数之后,严格遵循从左到右的运算。

计算逆波兰表达式的值时需要使用栈存储操作数,从左到右遍历并计算。具体操作如下:

  • 如果遇到操作数,则将操作数入栈;
  • 如果遇到运算符,则将两个操作数出栈,其中先出栈的是第二个操作数,后出栈的是第一个操作数,使用运算符对两个操作数运算,得到新操作数,将新操作数入栈。

遍历结束之后,栈内只有一个元素,该元素即为逆波兰表达式的值。

下图为示例 1 的计算逆波兰表达式的过程。

10_1.png

代码

  1. class Solution {
  2. public int evalRPN(String[] tokens) {
  3. Deque<Integer> stack = new ArrayDeque<Integer>();
  4. int length = tokens.length;
  5. for (int i = 0; i < length; i++) {
  6. String token = tokens[i];
  7. if (isNumber(token)) {
  8. stack.push(Integer.parseInt(token));
  9. } else {
  10. int num2 = stack.pop();
  11. int num1 = stack.pop();
  12. switch (token) {
  13. case "+":
  14. stack.push(num1 + num2);
  15. break;
  16. case "-":
  17. stack.push(num1 - num2);
  18. break;
  19. case "*":
  20. stack.push(num1 * num2);
  21. break;
  22. case "/":
  23. stack.push(num1 / num2);
  24. break;
  25. default:
  26. }
  27. }
  28. }
  29. return stack.pop();
  30. }
  31. public boolean isNumber(String token) {
  32. return Character.isDigit(token.charAt(token.length() - 1));
  33. }
  34. }

复杂度分析

  • 时间复杂度:栈题目:逆波兰表达式求值 - 图23#card=math&code=O%28n%29&id=STr2a),其中 栈题目:逆波兰表达式求值 - 图24 是数组 栈题目:逆波兰表达式求值 - 图25 的长度。需要遍历数组 栈题目:逆波兰表达式求值 - 图26 一次,计算逆波兰表达式的值。
  • 空间复杂度:栈题目:逆波兰表达式求值 - 图27#card=math&code=O%28n%29&id=rgmo5),其中 栈题目:逆波兰表达式求值 - 图28 是数组 栈题目:逆波兰表达式求值 - 图29 的长度。空间复杂度主要取决于栈空间,栈内元素个数不会超过逆波兰表达式的长度。

解法二

思路和算法

解法一使用栈存储操作数。也可以使用数组模拟栈操作。

对于长度为 栈题目:逆波兰表达式求值 - 图30 的逆波兰表达式,其中有 栈题目:逆波兰表达式求值 - 图31 个操作数和 栈题目:逆波兰表达式求值 - 图32 个运算符。当遇到操作数时,将操作数入栈,栈内元素个数加 栈题目:逆波兰表达式求值 - 图33;当遇到运算符时,将 栈题目:逆波兰表达式求值 - 图34 个操作数出栈,使用运算符运算后得到 栈题目:逆波兰表达式求值 - 图35 个新的操作数并入栈,因此栈内元素个数减 栈题目:逆波兰表达式求值 - 图36。根据上述分析可知,栈内元素个数不会超过原始逆波兰表达式中的操作数个数,即任何时候栈内元素个数不会超过 栈题目:逆波兰表达式求值 - 图37。因此,使用数组模拟栈操作时,将数组的长度定义为 栈题目:逆波兰表达式求值 - 图38 即可。

数组的左端即下标 栈题目:逆波兰表达式求值 - 图39 的位置为栈底。使用 栈题目:逆波兰表达式求值 - 图40 表示栈顶元素所在下标,初始时 栈题目:逆波兰表达式求值 - 图41,表示栈为空。

当元素入栈时,首先将 栈题目:逆波兰表达式求值 - 图42 的值加 栈题目:逆波兰表达式求值 - 图43,然后将入栈元素赋值到下标 栈题目:逆波兰表达式求值 - 图44 处。

当元素出栈时,首先获得下标 栈题目:逆波兰表达式求值 - 图45 处的元素,然后将 栈题目:逆波兰表达式求值 - 图46 的值减 栈题目:逆波兰表达式求值 - 图47

遍历结束之后,栈内只有一个元素,此时 栈题目:逆波兰表达式求值 - 图48,位于下标 栈题目:逆波兰表达式求值 - 图49 处的元素即为逆波兰表达式的值。

代码

  1. class Solution {
  2. public int evalRPN(String[] tokens) {
  3. int length = tokens.length;
  4. int[] stack = new int[(length + 1) / 2];
  5. int top = -1;
  6. for (int i = 0; i < length; i++) {
  7. String token = tokens[i];
  8. if (isNumber(token)) {
  9. stack[++top] = Integer.parseInt(token);
  10. } else {
  11. int num2 = stack[top--];
  12. int num1 = stack[top--];
  13. switch (token) {
  14. case "+":
  15. stack[++top] = num1 + num2;
  16. break;
  17. case "-":
  18. stack[++top] = num1 - num2;
  19. break;
  20. case "*":
  21. stack[++top] = num1 * num2;
  22. break;
  23. case "/":
  24. stack[++top] = num1 / num2;
  25. break;
  26. default:
  27. }
  28. }
  29. }
  30. return stack[top];
  31. }
  32. public boolean isNumber(String token) {
  33. return Character.isDigit(token.charAt(token.length() - 1));
  34. }
  35. }

复杂度分析

  • 时间复杂度:栈题目:逆波兰表达式求值 - 图50#card=math&code=O%28n%29&id=bszA7),其中 栈题目:逆波兰表达式求值 - 图51 是数组 栈题目:逆波兰表达式求值 - 图52 的长度。需要遍历数组 栈题目:逆波兰表达式求值 - 图53 一次,计算逆波兰表达式的值。
  • 空间复杂度:栈题目:逆波兰表达式求值 - 图54#card=math&code=O%28n%29&id=ywl6S),其中 栈题目:逆波兰表达式求值 - 图55 是数组 栈题目:逆波兰表达式求值 - 图56 的长度。空间复杂度主要取决于模拟栈操作的数组,其长度为 栈题目:逆波兰表达式求值 - 图57