Python技术迷

被打了低绩效还pua了一顿,结果有次无意发现我工作量在部门数一数二,干活干的比别人多很多…

网上有哥们吐槽:低绩效先来一张,顺便再被PUA一顿,回头一看数据才发现——自己工作量在部门里能排前二,干得比不少人多一截,结果一边猛搬砖一边拿“差评”,整个人像个二百五被转着圈耍。

Image

网友们也不惯着:有人说“你这是免费当了组里的缓存,谁卡了都来找你”;有人更直白:“别自证勤奋了,先自证边界”;还有人补刀:“绩效不是统计题,是人情题。”

我觉得这事挺扎心,写代码最怕隐形需求,职场最怕隐形标准。活可以干,锅别全背,留好记录,把任务排期、产出影响说清楚;实在还被压着打,就把简历当版本迭代,别让自己一直当测试环境。

算法题:以图判树

那天我在公司楼下买咖啡,排队的时候手机叮一下,群里有人丢了个算法题,说“以图判树”,我当时脑子里第一反应不是图论哈,是…哎这不就跟排查线上链路一样么,你得确认它是不是“一条主线”别分叉也别绕回来。之前看人抓包卡 1024 那个事儿,也是绕来绕去最后发现是“读错位导致成环”那种味道,反正就那种一眼看不出问题、细抠才发现关键条件漏了的感觉。

以图判树这题一般默认是无向图哈(大多数平台是这样),输入给你 n 个点、m 条边,问是不是一棵树。你别被“树”俩字骗了,核心就俩条件: 1)不能有环(你走着走着不能回到走过的地方) 2)得连通(不能有孤岛,不然就成森林了)

我以前写的时候老喜欢上来就 DFS,后来发现最省事的判断其实是:树一定满足 m = n - 1。这个条件太香了,因为只要边数不是 n-1,直接 false,别浪费时间。然后再做一次连通性检查就完事。 但注意哈,有些数据会恶心你:自环 (u==v)、重边 (u,v) 重复,都会让“看起来像 n-1”其实已经不对劲了,不过大部分判树的标准里,只要出现环(重边也会形成长度为2的环),就算 false。

我这里给一份我平时最常用的写法:并查集(DSU)。为啥用它?因为它天生就是干“连通 + 判环”这活的:

  • 合并前如果发现两个点已经在一个集合里,那条边一加就成环
  • 最后看是不是只剩一个连通块(或者看边数 + 无环即可推连通也行,但我还是会显式数一下集合,稳一点)

直接上代码,能跑就行,别整花活:

from typing import List, Tuple

classDSU:
def__init__(self, n: int):
        self.parent = list(range(n))
        self.rank = [0] * n
        self.components = n  # 连通块数量

deffind(self, x: int) -> int:
while self.parent[x] != x:
            self.parent[x] = self.parent[self.parent[x]]  # 路径压缩(折半)
            x = self.parent[x]
return x

defunion(self, a: int, b: int) -> bool:
        ra, rb = self.find(a), self.find(b)
if ra == rb:
returnFalse# 已经连通了,再连就是环
if self.rank[ra] < self.rank[rb]:
            ra, rb = rb, ra
        self.parent[rb] = ra
if self.rank[ra] == self.rank[rb]:
            self.rank[ra] += 1
        self.components -= 1
returnTrue

defis_tree(n: int, edges: List[Tuple[int, int]]) -> bool:
# 常见默认:点编号 0..n-1
# 1) 边数先卡死
if n <= 0:
returnFalse
if len(edges) != n - 1:
returnFalse

    dsu = DSU(n)

for u, v in edges:
# 基本防御:越界、self-loop
ifnot (0 <= u < n and0 <= v < n):
returnFalse
if u == v:
returnFalse
ifnot dsu.union(u, v):
returnFalse# 出环了

# 2) 连通性:树必须只有一个连通块
return dsu.components == 1

# 随手测两下
if __name__ == "__main__":
    print(is_tree(5, [(0,1),(1,2),(2,3),(3,4)]))  # True
    print(is_tree(5, [(0,1),(1,2),(2,0),(3,4)]))  # False 有环且不连通
    print(is_tree(1, []))                         # True 单节点也算树

你看这东西写完其实特别像排查故障:先用“边数=n-1”这种硬指标把 80% 的垃圾输入干掉,然后再用 DSU 逐条边去“合并链路”,一旦发现已经在同一个集合里还硬要连,那就是绕回来了,直接判环,结束。

哦对,还有个小坑:n=1 的时候,边是 0 条,这个是树(单节点树),别手滑写成 n==1 return False 这种低级错,我以前真踩过…当时还嘴硬说“这也算树吗”,后来发现题库就是这么定义的,没辙。