Python技术迷

华子员工爆料:领导问我愿不愿意到非洲上班,工资45000元,5年,双倍年终奖。

刚看到个贴子,说华子员工被问愿不愿去非洲上班,工资四万五一个月,干五年还有双倍年终奖。

Image

网友评论两极分化,有人说天价诱惑,干完回来能半躺一辈子;也有人说命没了钱有啥用,蚊子比人还多。

我觉得这事吧,得看人怎么看“值”。在国内卷得要死,一个月也就一两万,996不见得轻松;去非洲虽然远点苦点,但待遇是真实打在卡上的。其实职场永远是交换,拿高薪就得付出对应的辛苦和风险。

从另一个角度看,像这种机会,对年轻人可能是历练,对有家有口的人可能是负担。没人能替你算这笔账。工作没有完美选项,只有你能接受的代价。

选择去或不去,都别被别人左右。关键是清楚自己要什么,知道自己能承受什么。【备注:文末可领最新资料】

面试题:预测赢家

昨晚十一点多,在公司楼下等外卖,风有点大,我缩着脖子刷题。我们组那个小李突然语音问我:“东哥,那个…预测赢家咋写来着?”我一口奶茶差点喷出来,这题啊,别慌,思路其实不绕。

有一排分数牌 nums,两个人轮流拿,每次只能拿最左或最右。俩人都很聪明(就是那种你想的他也想到),问先手能不能赢(平局也算能“赢”)。听起来像斗地主?不是,就是博弈+区间。

对吧,其实关键就一句:当前玩家在区间 [i, j] 上,最多能比对手多拿多少分。只要这个“分差”从整段 [0, n-1] 看是 ≥ 0,先手就不亏。

核心想法就一条

设 dp[i][j] 表示“在 nums[i..j] 这段里,当前回合的玩家与对手的净胜分的最大值”。 为什么是净胜分?因为你拿到的分会变成对手的负分(回合切换),于是有个漂亮的转移:

dp[i][j] = max(
  nums[i] - dp[i+1][j],   # 拿左边,下一回合对手在 [i+1, j] 的净胜分会抵消你
  nums[j] - dp[i][j-1]    # 拿右边,同理
)

边界:i == j 时,只有一张牌,你拿走它,净胜分就是 nums[i]。

写两种:递归记忆化 & 迭代DP(都很顺手)

说到这儿我手机又响…等下我接个电话。好了继续。

递归 + 记忆化

这个更贴合上面的定义,代码短、好读。

from functools import lru_cache

defpredict_the_winner(nums):
    n = len(nums)
    @lru_cache(maxsize=None)
defdiff(i, j):
if i == j:
return nums[i]
        left = nums[i] - diff(i + 1, j)
        right = nums[j] - diff(i, j - 1)
return left if left >= right else right
return diff(0, n - 1) >= 0

迭代(自底向上)

有时候面试官爱看表格推进的感觉,也给一版。注意遍历顺序要按区间长度从小到大。

defpredict_the_winner_dp(nums):
    n = len(nums)
    dp = [[0]*n for _ in range(n)]
for i in range(n):
        dp[i][i] = nums[i]
for length in range(2, n+1):
for i in range(0, n - length + 1):
            j = i + length - 1
            dp[i][j] = max(nums[i] - dp[i+1][j],
                           nums[j] - dp[i][j-1])
return dp[0][n-1] >= 0

为啥这就对了

你当前回合能拿到的“优势”,等于你现在拿的一张,减去对手在剩余区间里能从你那儿抢回去的优势。俩人都最优,所以把对手看作“会把你的优势化为劣势”的那个 -dp[...]。这就把博弈变成了区间DP的常规套路。

复杂度、边角料和两个坑

  • 复杂度:O(n^2) 状态,每个状态 O(1) 转移;空间 O(n^2)。记忆化平均也差不多。
  • 坑一:别写成“当前玩家最大得分”,那样要同时记录两个人分数,写着写着就乱了;用净胜分一把梭。
  • 坑二:有同学说“长度为偶数先手必赢”,嗯…在这题里先手至少不输(>=0),但直接硬背结论不如写个 dp 稳妥,数据一变你就…你懂的。

小测一下

print(predict_the_winner([1,5,2]))       # False
print(predict_the_winner([1,5,233,7]))   # True
print(predict_the_winner_dp([1,5,2]))    # False
print(predict_the_winner_dp([1,5,233,7]))# True

行吧我这奶茶也快化了,总之就是:把“拿牌”变成“差值”,区间两端试一下,谁让对手更难受就选谁。哦对了,回头我把这两版丢到我们组的工具箱里…算了等会儿再说,我外卖到了先去拿。

-END-

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

🔥虎哥私藏精品🔥

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