Python技术迷

被组内37岁老嫡针对,大概率年底要被搞走。有没有反击的办法?

刚看到个贴子,说有网友被组内37岁的老嫡针对,大概率年底要被搞走,还在问有没有反击办法。

Image

我觉得这事吧,反击是要有智慧的,不是硬碰硬。

像这种被盯上的情况,说明你身上有点让对方不安的地方,要么是你做得太好,要么是太没防备。网友有人建议正面对抗,我倒觉得没必要。老嫡那套手段多半靠“嘴”,你要靠“手”——把事情做得滴水不漏,把价值摆在那儿,他再阴你也动摇不了。

另外,别单打独斗,适当培养自己的“盟友”,哪怕只是让大家觉得你靠谱、好合作,也能减少被孤立的风险。

别想着整他,先保自己。职场最硬的反击,就是让对方发现:就算他搞你,你也活得比他更稳、更值钱。【备注:文末可领最新资料】

面试题:万灵之树

有 n 颗宝石,数值是 gem[i]。我们要把它们当成二叉树的叶子;内部结点不限量,但每个内部结点必须恰好有 2 个子结点(也就是一棵满二叉树)。能量从根进树,规则是——到一个结点第一次就记下数字 1;如果它是叶子,再把这颗宝石的十进制数值也接在后面;当它所有子结点都“到过”时,记下 9 再回父结点。把全过程记下的数字顺序拼成一个大整数 num,要求 num % p == target。问:有多少种树形 + 叶子排列能满足?(题面出自 LCP 82)(力扣[1])

这个“记数过程”其实就是一条固定的遍历模板: 对一个形状确定的满二叉树,按“到达记 1、叶子再记宝石值、回溯记 9”的规则,能抽象成一串 token:1 (左子模板) (右子模板) 9;叶子则是 1 L(L 代表“在这里放一个宝石的十进制串”)。 所以问题分两层:

  1. 树形:n 片叶子的满二叉树数量是 Catalan 数 C_{n-1};
  2. 宝石顺序:落在模板里 n 个 L 的位置,放入 gem 的一个排列。num 巨大,不可能真的拼。关键是一路取模:
  • 往尾部追加一个十进制数字 d 等价于 num = (num*10 + d) % p;
  • 往尾部一次性追加一个整数 v(十进制长度 len)等价于 num = (num * 10^len + v) % p。 因此,我们可以对模板从左到右做 DP,遇到 1/9 就加一位,遇到 L 就在未用的宝石里任选一颗,把它的十进制整体“压进去”。这样避免了真的拼大数。

关键细节

  • 先生成所有满二叉树形状(用“叶子数”做记忆化拆分:n = i + (n-i))。

  • 对每个树,先做一遍 DFS 落出模板(只含 1、9、L)。

  • 预处理 pow10[k] = 10^k % p 以及每颗宝石的十进制长度 digits[i] 与 gem[i] % p。

  • 然后对模板做记忆化搜索:状态是 (pos, usedMask, curMod),转移:

    • 遇到 1/9:curMod = (curMod*10 + d) % p;
    • 遇到 L:枚举未使用的宝石 i,curMod = (curMod * pow10[digits[i]] + gem[i]%p) % p。
  • 终点 pos == len(template) 时,若 curMod == target 计数 +1。

  • 对所有树形求和即答案。 (当 n 稍大时可加“折半 + 形状分治”等优化;这里给出的是清晰易懂的直观写法。)

Python 实现

from functools import lru_cache
from math import log10

defsolve(gem, p, target):
    n = len(gem)
# 预处理宝石十进制长度与取模
defdigits_len(x):
return1if x == 0else int(log10(abs(x))) + 1
    g_mod = [x % p for x in gem]
    g_len = [digits_len(x) for x in gem]

# 10 的幂
    max_len = max(g_len) if g_len else1
# 模板长度上界 ~ 2*n + sum(len), 这里预个安全长度
    pow10 = [1] * (2 * n * (max_len + 2) + 5)
for i in range(1, len(pow10)):
        pow10[i] = (pow10[i-1] * 10) % p

# 生成所有满二叉树形状(用“叶子数”计数)
classNode:
        __slots__ = ("left", "right")
def__init__(self, left=None, right=None):
            self.left, self.right = left, right

    @lru_cache(None)
defgen_shapes(k):# 生成有 k 个叶子的所有树
if k == 1:
return (Node(),)  # 叶子用 left/right 都为 None 表示
        res = []
for i in range(1, k):
for L in gen_shapes(i):
for R in gen_shapes(k - i):
                    res.append(Node(L, R))
return tuple(res)

# 把树形转换为模板:内部结点 -> "1 ... 9",叶子 -> "1 L"
defto_template(root, buf):
if root.left isNoneand root.right isNone:  # 叶
            buf.append(1)   # 用 1 表示数字1
            buf.append('L') # 这里放一个宝石
return
        buf.append(1)
        to_template(root.left, buf)
        to_template(root.right, buf)
        buf.append(9)

# 对一个模板做记忆化计数
defcount_for_template(tmpl):
        m = len(tmpl)

        @lru_cache(None)
defdfs(pos, usedMask, curMod):
if pos == m:
return1if curMod == target else0
            tok = tmpl[pos]
# 数字 1 或 9
if tok != 'L':
return dfs(pos + 1, usedMask, (curMod * 10 + tok) % p)
# 遇到 L:选一颗没用过的宝石
            ans = 0
for i in range(n):
if (usedMask >> i) & 1: 
continue
                newMod = (curMod * pow10[g_len[i]] + g_mod[i]) % p
                ans += dfs(pos + 1, usedMask | (1 << i), newMod)
return ans

return dfs(0, 0, 0)

    ans = 0
for shape in gen_shapes(n):
        tmpl = []
        to_template(shape, tmpl)
        ans += count_for_template(tuple(tmpl))
return ans

# 示例
if __name__ == "__main__":
    gem = [3, 14, 159]
    p = 97
    target = 42
    print(solve(gem, p, target))

复杂度与可扩展

教学版代码的时间主要来自每个树形上的 (pos, usedMask, curMod) 状态。curMod 维度是 p,所以当 p 很大或 n 稍大(例如 ≥10)就吃紧了。工程上可做两类优化:

  • 折半:把模板在某个结点切开,左侧枚举得到 (mod) 多重计数表,右侧逆向“卷回”,最后按同余条件配对。
  • 形状复用:相同“叶子计数分布”的子树可以共享子 DP 结果,降低重复。

题目背景与更完整描述可见 LCP 82「万灵之树」。

-END-

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

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领