同事 40岁被裁员了,签了保密协议,每个月给88000补贴,连续给12个月,第二年减半,不能去同行公司,担心在家呆两年就废了!
刚看到个贴子,说有网友吐槽:同事40岁被裁,签了保密协议,不能去同行,每个月补贴88000给一年,第二年还减半。看着钱不少,但人家却担心两年在家会被时代淘汰。
我觉得这事吧,钱只是表面风光,背后的无力感外人真不一定懂。网友们有的说“在家躺两年不香吗”,但换个角度想,人到中年被按下暂停键,其实挺像高速行驶的车突然熄火,心里难免慌。
我的看法是,这补贴更像“缓冲期”,不是让你躺平,而是给你时间回血、学习、调整。40岁不是终点,但确实不能像二十几岁那样拍脑袋就换赛道。利用这段时间沉淀、补技能、想清楚下一步,反而是难得的窗口期。【备注:文末可领最新资料】
面试题:用队列实现栈
就拿最近一次面试说事儿哈,我在会议室那边刚坐下没两分钟,对面面试官就来一句:“用队列实现一个栈,语言随便,你不是写 Python 多吗?”这个题八股大家都见过,但真让你从零写个类,很多人还是会卡一下。
先把概念捋顺一下,别急着写代码
栈是啥?栈就是后进先出:最后压进去的,最先被弹出来,像你往杯子里丢硬币,永远是最上面那个先拿走。 队列反过来,先进先出,排队打饭那个感觉,先来的先走,后来的在屁股后头慢慢等。
题目就有点坏:只能用“排队打饭”的工具(队列),搞出一个“从上面掏硬币”的东西(栈)。 核心问题就一句话:怎么让“后来的人”在队列的“前面”被取出来。
先用两条队列糊一个出来试试
思路特别像搬家: 你想拿到最后一个箱子,就得先把前面的都搬到旁边去,等把最后一个拿出来,再把前面那些搬回来。
我们就准备两个队列:q1、q2,约定:
所有元素平时都在 q1 里 pop的时候,借用一下q2当临时存放区
大概流程你脑补一下:
push(x):简单,直接往q1里排队就行pop():
把 q1里前面的元素一个个出队,丢到q2,直到只剩最后一个q1里剩下的那个,就是“栈顶”,把它拿出来当返回值然后交换 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
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。