Python技术迷

和同事嬉戏打闹,一不小心亲了他一口,现在应该怎么收场?

刚看到个贴子,说有网友跟同事打闹打着打着,一激动亲上去了,现在整个人都尴尬到原地蒸发。

Image

我觉得这事吧,关键不是“亲了没”,而是你们平时的关系到底是什么程度。如果只是普通同事,那这一下确实容易惹麻烦,尤其职场这种地方,八卦传播速度比WiFi还快。

最稳妥的处理方式就是主动、轻描淡写地解释一下,类似“刚才闹过了,不好意思哈”,给个台阶,也给彼此边界划清。

如果对方也大方,那这事就过去了;如果对方明显不自在,那你之后更得注意保持距离,别再给别人造成压力。

坦诚一点,稳住心态,不逃不凶,这事还是能圆回来的。毕竟,职场风大,别让一时的失误影响了正常工作。【备注:文末可领最新资料】

面试题:基本计算器

说“基本计算器”这个题啊,其实就是面试里那种:给你一串字符串形式的算式,让你自己写代码算结果。看着像小学生口算,细节一多,很多人就翻车了 😂

下面我们就用 Python 写一个支持 + - () 的“基本计算器”,像力扣 224 那种,不搞 * /,先把核心思路吃透。

题目大概长这样(伪版):

  • 输入:一个只包含

    • 数字(可能是多位数)
    • 加号 +
    • 减号 -
    • 括号 ()
    • 以及若干空格 的字符串,比如:"1 + (2 - 3) + 4"
  • 输出:这个算式计算出来的整数结果,比如上面那个就是 4

没有乘除,没有小数,没有负号在数字前那种奇怪形式,一切都很“朴素”,但括号一来,大家就容易写成一坨 if-else 地狱。

模拟你手算的过程

你脑子里一般是这么算的:

  1. 从左往右扫

  2. 遇到数字就往后拼:看到 1、2、3 组合成 123

  3. 遇到 + 或 -,就把前面攒好的数字按之前的符号加到当前结果上,然后更新“当前符号”

  4. 括号怎么办?

  • 遇到 (,你会“暂存”当前算到哪了,等括号里面算完再合回来
  • 遇到 ),就先把括号里的小结果算出来,再带上进入括号前的符号,和外面的结果合并

翻译成代码友好的模型,就是:

  • 一个当前结果 res,表示“当前这一层括号里的和”
  • 一个当前的符号 sign,只有两种:+1 或 -1
  • 一个当前正在读的数字 num
  • 再加一个栈 stack,专门用来“保存遇到左括号时的现场”

每一步怎么干?

  • 遇到数字:num = num * 10 + int(ch)(处理多位数)

  • 遇到 + / -:

    • 先把之前的 num 刷进 res:res += sign * num
    • 然后更新 sign 为当前符号
    • 再把 num 清零
  • 遇到 (:

    • 先把当前的 res 和 sign 依次丢进栈里保存
    • 然后重置:res = 0,sign = 1,相当于进了一个“新的小世界”
  • 遇到 ):

    • 先和前面一样,把当前 num 结清:res += sign * num
    • 然后从栈里弹出之前保存的:先是 prev_sign,再是 prev_res
    • 新的 res = prev_res + prev_sign * res,也就是“外层结果 + 外层符号 ×(括号里的结果)”
    • 最后把 num 清零
  • 空格:直接忽略

字符串扫完以后,别忘了把最后一个 num 也加进去一次(因为结尾可能是数字,不会再触发符号去结算它)。

直接给你一个可以过题的版本,函数签名跟力扣那题一致:

classSolution:
defcalculate(self, s: str) -> int:
        stack = []      # 栈:保存进入每一层括号之前的 (res, sign)
        res = 0# 当前这一层的结果
        num = 0# 当前正在读取的数字
        sign = 1# 当前符号,1 表示 + ,-1 表示 -

for ch in s:
if ch.isdigit():
# 处理多位数,比如 "123"
                num = num * 10 + int(ch)
elif ch == '+'or ch == '-':
# 碰到运算符,先把前面的数字结算进 res
                res += sign * num
                num = 0
# 更新当前符号
                sign = 1if ch == '+'else-1
elif ch == '(':
# 进新括号:先把当前状态压栈
                stack.append(res)
                stack.append(sign)
# 重置当前层
                res = 0
                sign = 1
elif ch == ')':
# 先把括号里的最后一个数字结算
                res += sign * num
                num = 0
# 恢复外层的 sign 和 res
                prev_sign = stack.pop()
                prev_res = stack.pop()
# 外层结果 + 外层符号 * 括号内结果
                res = prev_res + prev_sign * res
else:
# 空格之类的直接跳过
continue

# 字符串扫完,还可能剩一个 num 没加
        res += sign * num
return res

你可以自己测几个例子,比如:

  • "1 + 1" → 2
  • " 2-1 + 2 " → 3
  • "(1+(4+5+2)-3)+(6+8)" → 23

拿这个函数跑一跑就能感受到逻辑还是很顺的。

再用一个例子走一遍流程

以 "1-(2-3)" 为例,大致是这样:

  • 一开始:res = 0, sign = 1, stack = []
  • 读到 1:num = 1
  • 读到 -:结算:res = 0 + 1*1 = 1,sign = -1,num = 0
  • 读到 (:把外层状态压栈:stack = [1, -1],然后 res = 0, sign = 1
  • 读到 2:num = 2
  • 读到 -:res = 0 + 1*2 = 2,sign = -1,num = 0
  • 读到 3:num = 3
  • 读到 ):先结算括号内:res = 2 + (-1)*3 = -1再从栈里弹出:prev_sign = -1, prev_res = 1外层结果:res = 1 + (-1)*(-1) = 2,刚好是 1 - (2 - 3) 的结果

这样走一遍你就会发现:其实就是“人脑算式”的程序化版本。

复杂度这块很简单:

  • 时间复杂度:O(n),只扫一遍字符串
  • 空间复杂度:O(n),最坏情况括号层层嵌套,全靠栈保存状态

如果以后你要支持 */ 版本的“基本计算器 II / III”,核心变化就是:

  • 多一个“栈处理乘除优先级”或者
  • 写一套递归下降解析器

但今天这个只支持 + - () 的版本,先写熟练了,后面升级也就一层一层加细节。

你可以先把这段代码打到本地,随便造几组表达式玩一玩,有问题再喊我一起调。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领