两个摄像头监控我!离项后公司公司对我进行劝退,我不同意,公司现在用两个摄像头对我进行监控。
刚看到个贴子,一个网友说自己离项后,公司想劝退又不想赔,就把他工位安排在会议室,用两个摄像头死死对着他,明显就是想把人“耗”走。
说白了公司想用冷暴力逼你主动走,本质就是想省钱,这点心思别看不懂。 你想如果不是统一规范安装,而是只盯着你一个人,已经不只是“不尊重”,而是带点羞辱意味了,说白了,就是职场PUA升级成“电子看守”。
真要遇上这种情况,我的看法是:别冲动提离职,先保留证据——邮件、调岗通知、监控位置照片、聊天记录都留好,然后去咨询劳动仲裁或专业律师,按规则来解决。
不过话说回来,离开烂环境不是失败,能用规则保护自己、好好体面地走,才是真的赢。
算法题:相交链表
昨晚十一点多,我刚准备关电脑刷个短视频放松一下,我们组小李在群里敲我:“哥,相交链表那个题你咋写的?我指针脑袋又打结了。”我一看时间,算了,谁叫我嘴快说过“链表问题随便问”。
先把题目人话说一下哈:有两条单链表,前面各走各的,走着走着可能会并成一条 Y 型的路,也可能压根不相交。现在只给你两条链表的头结点 headA、headB,要你返回“相交的那个结点对象”。注意是“同一个结点”,不是值一样就算同一个,地址得一样,Python 里就是同一个对象。
你想象这样一张图:
A: a1 -> a2 -> c1 -> c2 -> c3
B: b1 -> b2 -> b3 -> c1 -> c2 -> c3
从 c1 开始,后面一截是共享的,这个 c1 就是相交点。
有些同学一上来就:那不简单,两层循环,A 的每个结点拿去和 B 的每个结点比一下,看是不是同一个对象,遇到就返回。是能写,就是 O(m*n),面试官一般会给你一个“你再想想”的眼神。
比较自然一点的是用个集合,把 A 的所有结点塞进去,扫 B 的时候,看当前结点在不在集合里,在就说明相交了。这种写法挺直观的,我当时就这么跟小李说的。
伪代码直接上 Python:
classListNode:
def__init__(self, x):
self.val = x
self.next = None
defget_intersection_node_set(headA: ListNode, headB: ListNode) -> ListNode | None:
ifnot headA ornot headB:
returnNone
seen = set()
cur = headA
while cur:
seen.add(cur) # 注意是结点对象,不是 cur.val
cur = cur.next
cur = headB
while cur:
if cur in seen:
return cur
cur = cur.next
returnNone
这个时间是 O(m+n),但多用了一个 set,空间 O(m)。面试一般会追问一句:“能不能只用 O(1) 额外空间?”这时候就该拿出那个经典的双指针“互换跑道”方法了。
这个思路当时我在公司楼下抽烟想明白的,真的,指针题别死盯着代码,画画路就清楚很多。想象两个小人:p1 从 A 链表头开始走,p2 从 B 链表头开始走,每次一步一步往后挪。
规定个奇怪但好用的规则: 谁先走到自己这条链表的尾巴(None),就立刻“换到对方链表的头”继续走。就像 A 跑完自己的赛道,再去跑 B 的赛道;B 也是跑完自己的再去跑 A 的。
神奇的地方在这——如果两条链表有相交,那俩人总会在相交点撞一头;如果根本不相交,两个人最后都会一起走到 None,一起结束。
用数学讲就是走的总路程一样:p1 走的是 lenA + lenB,p2 也是 lenB + lenA,所以他们第二圈的时候,要么在某个结点同时到达,要么在 None 同时到达。
别想太复杂,直接写代码更好理解:
classListNode:
def__init__(self, x: int):
self.val = x
self.next: 'ListNode | None' = None
defget_intersection_node(headA: ListNode | None,
headB: ListNode | None) -> ListNode | None:
# 有任何一条是空,肯定不相交
ifnot headA ornot headB:
returnNone
p1, p2 = headA, headB
# 最多绕两圈,要么在交点相遇,要么同时到 None
while p1 isnot p2:
p1 = p1.next if p1 else headB # A 走完换到 B
p2 = p2.next if p2 else headA # B 走完换到 A
# 要么是交点结点,要么是 None
return p1
小细节说两句,你们写的时候容易翻车的地方:
比较一定用 is,因为我们要的是“同一个结点对象”,不是值相等。循环条件写成 while p1 != p2也行,在 Python 里效果一样,但is更语义化一点。一定要允许 p1或p2变成None后再“换头”。所以那两行写成「如果是 None 就跳到对方头」,而不是直接p1 = p1.next硬走,不然会报错。别忘了开头那个空链表判断,不然面试官会顺手补一个边界用例,把你卡掉。
小李当时问我一个好问题:“为啥这样不会死循环啊,看着两个人来回乱跑?”你可以脑子里把路摊平了画一下:A 路 + B 路 是一条长路,B 路 + A 路 也是一样长的一条,只不过起点不一样。俩人速度相同、每次都同步往前挪,总路程又一样,要么中途碰面,要么一起出界,不存在一个人永远在前面绕圈圈。
实际工程里呢,相交链表这种东西也常见,比如做一些复杂缓存、对象池,偷偷把两个链表尾部接在一起省内存,如果你不小心手动改指针,调试的时候能知道“这俩是不是其实接到一块了”,这个方法就很好用,直接借用业务对象本身的地址来判断。
行了,我这边咖啡也凉了,你可以先把这个双指针版敲一遍带案例自己跑跑,最好再手画两张长度不等、一个不相交的图,把指针移动过程按时间轴写下来,你就彻底不会忘了。等会我得去开个会,等下…
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB