Python技术迷

同事 40岁被裁员了,签了保密协议,每个月给88000补贴,连续给12个月,第二年减半,不能去同行公司,担心在家呆两年就废了!

刚看到个贴子,说有网友吐槽:同事40岁被裁,签了保密协议,不能去同行,每个月补贴88000给一年,第二年还减半。看着钱不少,但人家却担心两年在家会被时代淘汰。

Image

我觉得这事吧,钱只是表面风光,背后的无力感外人真不一定懂。网友们有的说“在家躺两年不香吗”,但换个角度想,人到中年被按下暂停键,其实挺像高速行驶的车突然熄火,心里难免慌。

我的看法是,这补贴更像“缓冲期”,不是让你躺平,而是给你时间回血、学习、调整。40岁不是终点,但确实不能像二十几岁那样拍脑袋就换赛道。利用这段时间沉淀、补技能、想清楚下一步,反而是难得的窗口期。【备注:文末可领最新资料】

面试题:用队列实现栈

就拿最近一次面试说事儿哈,我在会议室那边刚坐下没两分钟,对面面试官就来一句:“用队列实现一个栈,语言随便,你不是写 Python 多吗?”这个题八股大家都见过,但真让你从零写个类,很多人还是会卡一下。

先把概念捋顺一下,别急着写代码

栈是啥?栈就是后进先出:最后压进去的,最先被弹出来,像你往杯子里丢硬币,永远是最上面那个先拿走。 队列反过来,先进先出,排队打饭那个感觉,先来的先走,后来的在屁股后头慢慢等。

题目就有点坏:只能用“排队打饭”的工具(队列),搞出一个“从上面掏硬币”的东西(栈)。 核心问题就一句话:怎么让“后来的人”在队列的“前面”被取出来。

先用两条队列糊一个出来试试

思路特别像搬家: 你想拿到最后一个箱子,就得先把前面的都搬到旁边去,等把最后一个拿出来,再把前面那些搬回来。

我们就准备两个队列:q1、q2,约定:

  • 所有元素平时都在 q1 里
  • pop 的时候,借用一下 q2 当临时存放区

大概流程你脑补一下:

  • push(x):简单,直接往 q1 里排队就行

  • pop():

  1. 把 q1 里前面的元素一个个出队,丢到 q2,直到只剩最后一个
  2. q1 里剩下的那个,就是“栈顶”,把它拿出来当返回值
  3. 然后交换 q1 和 q2 的名字——以后继续用 q1 当主队列
  • top():和 pop 几乎一样,只是最后那个元素别扔掉,再塞回去

  • 用 Python 写出来大概长这样(为了简单,我直接用 collections.deque 当队列,popleft() 就是出队):

    from collections import deque

    classMyStack:
    def__init__(self):
    # q1 当“主队列”,q2 当“临时队列”
            self.q1 = deque()
            self.q2 = deque()

    defpush(self, x: int) -> None:
            self.q1.append(x)

    defpop(self) -> int:
    # 把 q1 里前面的都挪到 q2,只留最后一个
    while len(self.q1) > 1:
                self.q2.append(self.q1.popleft())
    # 此时 q1 里面只剩“栈顶”
            top_val = self.q1.popleft()

    # 交换 q1、q2,保证元素都回到 q1
            self.q1, self.q2 = self.q2, self.q1
    return top_val

    deftop(self) -> int:
    while len(self.q1) > 1:
                self.q2.append(self.q1.popleft())
    # 拿到栈顶,但不销毁
            top_val = self.q1.popleft()
    # 记得放回去
            self.q2.append(top_val)

    # 还是交换
            self.q1, self.q2 = self.q2, self.q1
    return top_val

    defempty(self) -> bool:
    return len(self.q1) == 0

    这个版本挺直观的,对吧,就是每次 pop/top 有点费劲,要不停倒来倒去,时间复杂度:

    • push:O(1)
    • pop / top:O(n)

    再抠一抠,其实一条队列也够用

    面试官一般都会追问一句:能不能只用一个队列? 其实思路就是反过来——把“麻烦”放在 push 上。

    想法是这样的: 每次 push(x) 之后,我们把队列里“除了 x 以外”的那些人全部挪到队尾。 这样一来,刚刚塞进去的 x 就会被“旋转”到队首。 那以后你 pop 的时候,直接 popleft(),拿到的就是“最近压入的那个”,自然就是栈顶。

    举个简单例子,你按顺序 push:1, 2, 3

    1. push(1)

    • 队列:[1](挪 0 次)
  • push(2)

    • 出 1、入 1,变成 [2, 1]
    • 先 append 2:[1, 2]

    • 当前长度 2,把前面 1 个挪到后面:

  • push(3)

    • 出 2、入 2 → [1, 3, 2]
    • 出 1、入 1 → [3, 2, 1]
    • 先 append 3:[2, 1, 3]

    • 当前长度 3,把前面 2 个挪到后面:

    你看,队首永远是最新压进去的那个,pop 就变成 O(1) 了。

    Python 代码长这样:

    from collections import deque

    classMyStack:
    def__init__(self):
            self.q = deque()

    defpush(self, x: int) -> None:
    # 先正常入队
            self.q.append(x)
    # 再把前面的都“旋转”到队尾
    # 旋转次数 = 之前已有的元素个数
    for _ in range(len(self.q) - 1):
                self.q.append(self.q.popleft())

    defpop(self) -> int:
    # 此时队首就是“栈顶”
    return self.q.popleft()

    deftop(self) -> int:
    return self.q[0]

    defempty(self) -> bool:
    return len(self.q) == 0

    这个版本的复杂度就反过来了:

    • push:O(n)(每次要旋转一圈)
    • pop:O(1)
    • top:O(1)
    • empty:O(1)

    一般在面试或者刷题里,大家都更喜欢这个单队列的写法,看起来更“聪明”一点,而且 pop 是高频操作,做到 O(1) 也更香。

    最后随口叨两句

    这个题其实是在考一个习惯:别盯着“栈”和“队列”的名字看,多想“元素顺序”怎么被你控制。 你只要搞明白“怎么让最新的那个元素出现在队首”,后面代码就都只是体力劳动了。

    要是你面试的时候被问到,心里先默念一句:

    “我要么在 push 时折腾顺序,要么在 pop 时折腾顺序,二选一。”

    然后挑一个你写得更顺手的版本撸出来,就差不多了。

    -END-

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

    🔥虎哥私藏精品🔥

    虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB。