Python技术迷

恶心死了,公司领导他爸生病住院,行政挨个工位来收“自愿捐款”,说“表达一下心意”,然后拿着本子登记,最低100块

领导他爸住院,按理说是私事,结果公司整得跟集体项目一样,行政抱个本子一排排问过去,嘴上叫自愿,手上先把台阶给你拆了,低于一百都不好意思写。你不掏钱,她那个表情,好像你欠的不是人情,是医药费。

Image

评论区也挺真实,有人说这哪是献爱心,这是变相收份子;还有人更直接,说公司最会拿员工的钱去做领导的人情。话糙但真是这么回事。

真想表达心意的人,自己私下转就完了。搞成当众登记、按工位扫荡,味儿一下就馊了。最烦这种假客气,嘴里讲温度,手上玩施压。最后很多人不是想捐,是怕被盯上,怕以后穿小鞋。钱不多,膈应是真膈应,一百块买了个“别给我记仇”,想想都晦气.

算法题:金字塔转换矩阵

底层只有一排字符,往上每次拿相邻两个字符,查规则表,拼出上一层。最后能不能一路堆到塔尖,只剩 1 个字符,这题看着像字符串题,真写起来很容易把自己绕进死递归。

这题我第一眼就不太信“暴力试一试”这种写法。原因很简单:同一层的某个相邻对,可能对应多个可选字符。比如 BC -> A/G/H,你只要在这一层选错一次,后面整棵搜索树都会歪。所以它本质不是构造题,是个带回溯的状态搜索题。

题目一般给你两个东西:

bottom = "BCD"
allowed = ["BCC", "CDE", "CEA", "FFF"]

"BCC" 的意思不是三个独立字符,而是:底层相邻的 BC,上面可以放 C。

先别急着 DFS,先把规则整理一下。现场里这种题,第一步不整理映射,后面代码八成会写得一团糊。

from collections import defaultdict

defbuild_graph(allowed):
    graph = defaultdict(list)
for rule in allowed:
        graph[rule[:2]].append(rule[2])
return graph

接下来就是核心: 先根据当前层,生成“上一层所有可能的字符串”; 再对这些候选继续递归。

这里有个细节很关键:不是一边扫一边递归往上跳,而是要先把“当前层的上一层候选”完整拼出来。这个顺序一乱,代码就开始拧巴。

from functools import lru_cache

defpyramid_transition(bottom, allowed):
    graph = build_graph(allowed)

    @lru_cache(None)
defdfs(row):
if len(row) == 1:
returnTrue

        candidates = []

defbacktrack(i, path):
if i == len(row) - 1:
                candidates.append("".join(path))
return

            key = row[i:i+2]
if key notin graph:
return

for ch in graph[key]:
                path.append(ch)
                backtrack(i + 1, path)
                path.pop()

        backtrack(0, [])

for nxt in candidates:
if dfs(nxt):
returnTrue
returnFalse

return dfs(bottom)

这段代码里,lru_cache 不是点缀,它是真能省事。因为同一个 row 可能从不同路径反复走到,比如 "ABCD" 这层,前面不同分支兜一圈又回来了,不缓存就会重复算。

举个例子:

print(pyramid_transition(
"BCD",
    ["BCC", "CDE", "CEA", "FFF"]
))

如果返回 True,说明存在一条合法路径,能把 "BCD" 一层层堆到塔尖。返回 False,就是中途总会卡住。

这题难点不在 DFS,难在两个地方。

一个是你得接受“同一对字符会对应多个结果”,所以不能贪心。 另一个是你得把搜索单位想清楚:递归的不是某个字符位置,而是“整一层字符串”。

很多人会把这题写成“当前层选一个,立刻递归下一个层级”,代码看着很忙,实际上状态都没收干净,调起来特别恶心。