Python技术迷

年薪 200w一直不生孩子的老婆,要不要离婚。结婚十年了都不生孩子,快奔四了,我自己年薪 100多。。

刚看到个贴子,说一对夫妻结婚十年,老婆年薪两百万却一直不肯生孩子,理由是“焦虑、没空、在卷大模型”。老公年薪一百万,快四十了,开始犹豫要不要离婚。

Image

我觉得这事吧,表面是“生孩子”的问题,实际是“人生选择”的不匹配。一个想要家庭,一个还在冲事业,十年都没磨合好,这不只是时间问题,是价值观根本不在一个频道。网友们有说女方太自我,也有说男方太功利,但说到底,两个人的节奏不同步,婚姻就很难舒服。

从我的角度看,结婚不是让对方按你的剧本生活。她有她的追求,你也有你的期待。要么沟通出共同的“未来计划”,要么就体面止损。婚姻不是输赢题,是合不合拍的问题。能互相成全最好,不能,就别互相耗着【备注:文末可领最新资料】

面试题:祖玛游戏

昨晚十一点多,在公司楼下吹风,手机里那个祖玛小游戏又卡我了…我一边啃鸡腿一边琢磨,这玩意儿其实就两件事:把连续≥3的球消掉,手里有几颗备用球往合适的位置插。听着简单,对吧?但真写起来,坑还挺多的,别急我慢慢说。

就是那个…怎么讲,暴力也能过,但得“精暴力”。我用深度优先搜索(DFS)配记忆化。状态长啥样?两部分:当前轨道的字符串 board,比如 "WRRBBW",还有手里各颜色的数量 hand,比如 "RB". 我把手里的球做个计数表,像 {'R':2,'Y':1,...},这样递归时能随手减一。

关键是每次尝试“在哪个位置插哪种颜色”。不是到处乱插哈,插的位置要“有意义”:至少左边或右边有同色,这样才可能触发消除,否则插了多半白搭。插完以后立刻做一轮“收缩”(我叫它 shrink),把所有连续≥3的段落干掉;注意这会连锁反应,要 while 循环一直消到不能消为止。然后继续递归。所有状态走过的,记到缓存里,下次别再跑一遍,省电。

两个小细节,容易翻车

一个是重复尝试:同一位置、同一种颜色,没必要反复插;我用一点点剪枝,比如相邻位置颜色一样就跳过一部分重复。另一个是结束条件:board 空了就赢,返回已用步数;手里没球了还没清空,直接判死路。还有个小策略——如果某个颜色的球手里一颗都没有,就别考虑它了,废话但好用。

复杂度别想太美

理论上分支很大,但靠“只在可消位置插”“立即收缩”“记忆化”几招,实际规模(祖玛题的输入都不大)就能跑得很利索。昨晚我这版跑小样本是稳的…呃等下,外卖来了…好了继续,上代码你抄就能用,别和我杠命名丑。

from functools import lru_cache
from collections import Counter

COLORS = "RYBGW"

deffindMinStep(board: str, hand: str) -> int:
# 手里球计数
    cnt = Counter(hand)

# 收缩函数:把 >=3 连续段消掉,直到稳定
defshrink(s: str) -> str:
        changed = True
while changed:
            changed = False
            i, n = 0, len(s)
            res = []
while i < n:
                j = i
while j < n and s[j] == s[i]:
                    j += 1
if j - i >= 3:   # 这一段可以消
                    changed = True
else:
                    res.append(s[i:j])
                i = j
            s = "".join(res)
return s

# 把手里球计数压成固定序列,方便记忆化
defpack_counts(c: Counter):
return tuple(c.get(ch, 0) for ch in COLORS)

    @lru_cache(None)
defdfs(cur_board: str, r: int, y: int, b: int, g: int, w: int) -> int:
        cur_board = shrink(cur_board)
ifnot cur_board:
return0# 清空了,不需要再用球

        hand_counts = Counter({
'R': r, 'Y': y, 'B': b, 'G': g, 'W': w
        })

        ans = float('inf')
        n = len(cur_board)

# 枚举插入位置
        i = 0
while i <= n:
# 小剪枝:相同颜色段的内部位置只试一次(选择段的左端)
# 这里让 j 指向当前位置右边同色段的末端
if i < n:
                j = i
while j < n and cur_board[j] == cur_board[i]:
                    j += 1
# 段 [i, j) 的左边插同色更有意义,段内其他点多数等价
else:
                j = i

for c in COLORS:
if hand_counts[c] == 0:
continue
# 只有当插入处与左右有同色时才尝试,增加触发消除的概率
                left_same = (i > 0and cur_board[i-1] == c)
                right_same = (i < n and cur_board[i] == c)
ifnot (left_same or right_same):
continue

# 再剪一刀:如果左边已经是同色,优先在段的最左插一次就够了
if left_same and i > 0and cur_board[i-1] == c:
# 保证只在一段的最左边试一次
if i > 0and (i == 0or cur_board[i-2] != c):
pass
# 构造新局面
                new_board = cur_board[:i] + c + cur_board[i:]
                hand_counts[c] -= 1
                res = dfs(
                    new_board,
                    hand_counts['R'],
                    hand_counts['Y'],
                    hand_counts['B'],
                    hand_counts['G'],
                    hand_counts['W'],
                )
                hand_counts[c] += 1
if res != -1:
                    ans = min(ans, res + 1)

# 跳到下一段起点,避免在同色段内重复插
            i = j if i < n else i + 1

return-1if ans == float('inf') else ans

return dfs(board, *pack_counts(cnt))


if __name__ == "__main__":
# 随便测两下
    print(findMinStep("WRRBBW", "RB"))        # -1
    print(findMinStep("WWRRBBWW", "WRBRW"))   # 2
    print(findMinStep("G", "GGGGG"))          # 2

行了就这样,我去热杯咖啡。对了有人问为啥要 shrink 到不能再消?因为连锁反应嘛,不消干净你下一步评估就会失真…算了不唠了,你跑跑看先。

-END-

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

🔥虎哥私藏精品🔥

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