LeetCode:经典题之150 题解与肢解

系列目录

88.合并两个有序数组
52.螺旋数组
567.字符串的排列
643.子数组最大平均数

150.逆波兰表达式
61.旋转链表
160.相交链表
83.删除排序链表中的重复元素

389.找不同
1491.去掉最低工资和最高工资后的工资平均值
896.单调序列

206.反转链表
92.反转链表II

141.环形链表
142.环型链表



150.逆波兰表达式

🌟逆波兰+栈

原题链接


逆波兰表达式本质就是一种后缀表达式

class Solution {
public:
    // 对 token 的任何修改都会传递给原始 string 对象上,因为传递的是引用而不是副本
    bool isNumber(string& token)
    {	
    	// 若 函数参数既非又非+-*/ 则 返回true
        return !(token == "+" || token == "-" || token == "*" || token == "/");
    }

    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        int n = tokens.size();
        for (int i = 0; i < n; i ++) {
            string& token = tokens[i];
            if (isNumber(token)) {
                // ASCII to Integer atoi()
                // 整数栈,需要将操作符这种char类型转换成对应的int型才能压入栈
                stk.push(atoi(token.c_str()));
            } else {
                // 先出栈的操作数应该放在操作符右边👉
                int num2 = stk.top();
                stk.pop();

                int num1 = stk.top();
                stk.pop();

                // token数组(剩余)第1个元素(必定为操作符)
                // 根据操作符进行相应的运算,并将结果推回栈中
                switch (token[0]) {
                    case '+':
                        stk.push(num1 + num2);
                        break;

                    case '-':
                        stk.push(num1 - num2);
                        break;

                    case '*':
                        stk.push(num1 * num2);
                        break;

                    case '/':
                        stk.push(num1 / num2);
                        break;
                }
            }
        } // for_end

        return stk.top();
    }
};

肢解剖析

string& token = tokens[i];

定义一个名为token的引用,它引用了tokens容器中索引为istring对象

之后,可通过token来访问和修改string对象,而不需要使用tokens[i]



atoi()

"ASCII to Integer"

定义在<stdlib.h>头文件中

实际上它并不是专门处理 ASCII 字符的,而是处理任何可表示为整数的字符串,即将字符串 (string )转换为整数 (integer )



stk.push(atoi(token.c_str()))

token 这个 string 类型的字符串转换为整数,并将这个整数推入 stk 这个整数栈

这行代码执行了以下几个操作:

  1. token.c_str()
    token 是一个 string 类型的引用

    c_str()string 类的一个成员函数,它返回一个指向正规 C 字符串的指针,内容与原 string 相同 这个 C 字符串以'\0'结尾

  2. atoi(token.c_str())

    atoi 是一个标准库函数 (定义在 <stdlib.h><cstdlib> 中 ),用于将 C 字符串 (即 char* 类型的字符串 )转换为 int 类型的整数

    这里,它将 token.c_str() 返回的 C 字符串转换为整数

  3. stk.push()
    stk 是一个 stack<int> 类型的对象,用于存储整数

    pushstack 类的一个成员函数,用于在栈顶添加一个新元素

    这里,它将 atoi(token.c_str()) 转换得到的整数推入栈中

这种转换和推(入)栈操作在逆波兰表达式求值算法中是很常见的

因为逆波兰表达式通常是由数字和操作符组成的字符串序列

需要将这些字符串转换为数字并存储在(整数)栈中以便后续计算



switch(开关)语句:

switch 语句是一些编程语言都可适用的用于多路分支选择的结构

允许你基于一个表达式的值的不同情况来执行不同的代码块

switch 语句的基本语法如下:

switch (expression) {  
    case constant1:  
        // 当 expression 的值等于 constant1 时执行的代码  
        break;  
    case constant2:  
        // 当 expression 的值等于 constant2 时执行的代码  
        break;  
    // ... 可以有更多的 case  
    default:  
        // 当 expression 的值不匹配任何 case 时执行的代码  
}
  • expression 是一个表达式,其值将被与 case 语句中的各个常量进行比较
  • case 关键字后面跟着一个常量表达式 (通常是整数或字符 ),如果 expression的值与该常量相等,则执行该 case 下的代码块
  • break 关键字用于终止 switch 语句,防止代码自动执行到下一个 case
  • default 是可选的,当 expression 的值不匹配任何 case 时,将执行 default 下的代码块


switch (token[0]) {}

这里 token 是一个字符串或字符数组,token[0]获取该字符串或字符数组的第一个字符



手动定义一个isNumber()方法(函数)

  • 判断一个字符串是否是操作数
  • 如果 token 不是 这四个操作符中的任何一个(即是一个操作数),则返回 true,否则返回 false

逆波兰表示法

逆波兰表示法(Reverse Polish Notation,RPN)是一种不需要括号来标明运算顺序的算术表示法
又称后缀表示法,波兰表示法即为前缀表达式
在逆波兰表示法中,操作符位于操作数之后,因此不需要括号来指明运算的优先级

在C++中,逆波兰表示法的一个常见应用是在实现计算器的表达式求值时
由于逆波兰表示法不需要括号,因此可以简化表达式的解析过程

示例:

#include <iostream>  
#include <stack>  
#include <string>  
#include <sstream>  
#include <cctype>  
  
// 函数声明  
double applyOp(double a, double b, char op);  
  
int main() {  
    std::string expression = "2 3 + 4 *"; // 逆波兰表示法的表达式 (2 + 3) * 4  
    std::stack<double> values;  
  
    std::istringstream iss(expression);  
    std::string token;  
  
    while (iss >> token) {  
        if (std::isdigit(token[0])) { // 如果token是数字,则压入栈  
            double value = std::stod(token);  
            values.push(value);  
        } else { // 如果token是操作符,则从栈中弹出两个操作数进行计算  
            double val2 = values.top();  
            values.pop();  
            double val1 = values.top();  
            values.pop();  
  
            double result = applyOp(val1, val2, token[0]);  
            values.push(result);  
        }  
    }  
  
    // 栈中剩下的就是最终的结果  
    std::cout << "Result: " << values.top() << std::endl;  
  
    return 0;  
}  
  
double applyOp(double a, double b, char op) {  
    switch (op) {  
        case '+':  
            return a + b;  
        case '-':  
            return a - b;  
        case '*':  
            return a * b;  
        case '/':  
            if (b != 0.0) return a / b;  
            else throw std::invalid_argument("Division by zero");  
        default:  
            throw std::invalid_argument("Invalid operator");  
    }  
}

注解:

  • 首先读取一个逆波兰表示法的字符串表达式,然后逐个处理每个token 如果token是一个数字,它将被转换为一个双精度浮点数并压入栈中
  • 如果token是一个操作符,它将从栈中弹出两个操作数,应用操作符进行计算,并将结果压回栈中
  • 栈中剩下的就是整个表达式的计算结果
  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值