2026/4/7 14:52:19
网站建设
项目流程
宿迁网站建设价位,抖音粉丝购买网站,中铁建设集团好进吗,互联网公司排名500强名单别被字符串骗了 — 从手撸计算器到一遍过的 Basic Calculator II
作者#xff1a;Echo_Wish先来一句实话#xff1a;这道题看起来像字符串题#xff0c;实际上考的是你对运算优先级、流式计算#xff08;streaming#xff09;和状态管理的理解。LeetCode 上的 Basic Calcu…别被字符串骗了 — 从手撸计算器到一遍过的 Basic Calculator II作者Echo_Wish先来一句实话这道题看起来像字符串题实际上考的是你对运算优先级、流式计算streaming和状态管理的理解。LeetCode 上的Basic Calculator II只有 - * /没有括号是刷题里经典的一道既能考你写出正确的实现也能让你在代码里体现工程思路 —— 安全、稳健、易读、可拓展。今天咱不走过场按“先讲直观原理 → 再讲常见思路 → 最后给出干净、高质量实现 解析”的路线把这题讲明白代码里全注释手把手教你为什么这么写。风格就像和老同学对面聊一句话一句敲清楚。题目回顾一句话版给定一个只包含非负整数、 - * /操作符和空格的字符串计算并返回表达式的值。除法按截断向零trunc toward zero处理。保证表达式有效。举个小例子32*2→7 3/2 →1整除截断 35 / 2 →5。看起来简单但坑在这儿*和/优先级比和-高。你需要在一次线性扫描里正确处理优先级而不是先分割再暴力算。直观思路口语版把表达式想成一条流水线你从左到右一口气读过去遇到数字就收集遇到操作符就根据上一个操作符决定怎么处理当前数字。关键思想之一是延后 和 - 的求和但立即完成 * / 的计算。也就是说当你看到*或/你必须立刻把上一个“待加入总和”的值与当前数字做掉乘除然后把结果继续作为“待加入总和”的值但当你看到或-时可以把之前的待加入值放进最终和或栈然后把当前数字作为新的待加入值记号由操作决定正负。两种常见实现栈stack方案遇到数字和操作符通过栈保存中间的带符号数*//立刻弹出栈顶与当前做运算并将结果推回结束后把栈里所有数相加。直观但需 O(n) 额外空间栈。常量空间方案lastNum 技巧不显式使用栈而是维护lastNumber相当于栈顶result当前总和不含lastNumbersign上一个操作符。遇到/-时把lastNumber加到result并将lastNumber设为当前数字或其负数遇到*//时直接修改lastNumber。遍历结束把lastNumber加到result即得答案。这个方案 O(1) 空间直观高效。我偏好第二种因为更简洁、内存友好同时逻辑也一清二楚result固定保存那些已经“结算”的加项lastNumber存储还没被加入result的那一项可能被后续*//改写。一个示例把流程走一遍表达式32*2-4/3逐步常量空间方案初始result 0,last 0,sign 读到3num3下一个是sign‘’) → 遇到把last(0)加到result-result0把last 3读到2num2下一个是*sign‘’, 当前符号是上一个 ‘’→ 遇到*不要把last加到result而是更新last last * num 3*2 6读到2num2下一个是-sign‘*’) → 遇到-把last(6)加到result-result6把last -2读到4num4下一个是/sign‘-’) → 遇到/更新last last / num -2 / 4截断向零等于0注意符号和截断…最终把last加回result得答案示例用于说明实际数值需按整数截断规则算清。注意截断向零的细节在 Python 中做整数除法要谨慎负数除法需要用 int(a/b) 而不是 //因为 // 是向下取整。代码实现Python含详细注释defcalculate(s:str)-int: 计算只包含非负整数和 - * / 空格的表达式结果。 思路一次遍历维护三个变量 - result: 已经结算并加入总和的部分不含 last_num - last_num: 当前“待加入”的数字这个数字会参与连续的 * / 运算 - sign: 上一个操作符决定如何处理当前读到的数 结束时返回 result last_num。 注意除法需按截断向零trunc toward zero在 Python 中需用 int(a / b) 来实现。 时间复杂度 O(n)空间 O(1)不计输入字符串。 ss.strip()ifnots:return0result0# 累积的和已结算last_num0# 上一个待结算的数字可能被 * / 连续修改num0# 当前读取的数字sign# 初始化为 , 便于处理第一个数字i0nlen(s)whilein:chs[i]ifch.isdigit():# 读取完整数字可能多位numnum*10(ord(ch)-ord(0))# 如果当前字符是运算符或者到达字符串末尾需要基于上一个 sign 把 num 处理进 last_num 或 resultif(notch.isdigit()andch! )orin-1:ifsign:# 把之前的 last_num 结算进 result新的 last_num 为当前 numresultlast_num last_numnumelifsign-:resultlast_num last_num-numelifsign*:last_numlast_num*numelifsign/:# 在 Python 中负数除法 // 是向下取整不是截断向零# 使用 int(a / b) 来实现截断向零行为# 注意last_num 可能为负数last_numint(last_num/num)# 重置 num并更新 sign 为当前运算符num0signch i1returnresultlast_num# 简单测试print(calculate(32*2))# 7print(calculate( 3/2 ))# 1print(calculate( 35 / 2 ))# 5复杂度与边界说明时间复杂度O(n)只遍历字符串一次数字字符也只被读一次。空间复杂度O(1)只用常量级额外变量。注意点数字可能多位字符串中有空格必须对负数除法做截断向零语言差异要处理。Echo_Wish 的一点感受收个尾这类题好在它能逼着你把“算法思想”落地为“工程代码”要考虑流式解析stream parsing、数字边界、符号优先级、语言语义细节例如 Python 的除法行为以及代码的可读性。刷题不仅是为了 AC更是为了把“一套优雅可复用的思考方式”刻进脑子里遇到字符串处理类的问题先想状态机然后把状态压缩成最小变量这套套路以后能省你大把时间。