Python技术迷

面了一个比我大8岁的前辈,某大厂前P7,曾经年薪百万的大佬。但他坐在我对面谈薪资时那种小心翼翼的眼神,让我心里特别不是滋味。

刚看到个贴子,说博主去面试,碰到个比他大8岁的前大厂P7,以前年薪百万,如今空窗11个月,只敢开口要20k,还一再表态“不挑活、能加班”。那一刻,他说仿佛看见了七年后的自己。

Image

网友回帖,有人感慨时代变了,也有人阴阳怪气:大厂光环不过如此。我觉得这事吧,挺扎心,但也挺现实:职场就像抢座位,音乐一停,总有人站着,轮到谁,有时候真不看资历。

从我的角度看,这个前辈不丢人,反而很清醒,放下面子,只想先活下去。真正该警醒的,是还在上班的人:别把Title当护身符,趁现在多攒钱、多练真本事,让自己以后哪怕掉队,也还有重新上桌的筹码。

算法题:盛最多水的容器

昨天晚上十一点多,我在公司楼下啃着个凉了的肉夹馍刷题,隔壁组一个小朋友突然问我:哥,你说两块木板中间倒水,怎么摆位置水最多?我脑子里先蹦出来的不是物理,是这道老网红题——“盛最多水的容器”。

先说下题大概啥意思哈: 给你一个数组 height,每个数就是一根竖着钉在 x 轴上的木板高度,木板间距都是 1。你随便挑两根木板,当成容器两边,中间装水,那容量怎么算?就是:

容量 = 两板之间的宽度 * 较矮那根板的高度

问你:所有可能的两根板里,能装的水最多是多少。

说人话就是:一排高矮不一样的杯子,任意选两个做一对,问哪一对“中间那块区域”装水最多。

有些同学第一反应特别自然:那就暴力呗,两个 for,所有组合都试一遍。

defmax_area_bruteforce(height):
    n = len(height)
    ans = 0
for i in range(n):
for j in range(i + 1, n):
            h = min(height[i], height[j])
            w = j - i
            area = h * w
if area > ans:
                ans = area
return ans

这玩意儿思路是没问题,逻辑也很清楚,就是有点…笨,时间复杂度 O(n^2),数据一上来就容易超时。面试官一般看到这只能跟你说一句:思路对,但还有没有更快的?

我当时在楼下就跟那小朋友说:你想象一下,不是一排数字,是一排真的木板,你人站在最左边和最右边,各拉着一块板,中间灌水。这时候宽度是最大的,对吧?那容量是多少呢?是:

(右边下标 - 左边下标) * min(左板高度, 右板高度)

关键问题来了:我下一步该动左边那块,还是右边那块?

很多人这里会犹豫,其实就一个原则:永远移动“矮”的那一边。

为啥?口语一点讲:

  • 假设左边比较矮,那现在容量受限的是左边这根矮板
  • 你要是往里面挪右边(高的那根),宽度变小了,高度还是取决于左边那根矮板 → 面积只会变小,不可能变大
  • 所以挪右边是纯亏本,没啥希望;那就只能赌一把,动左边,看能不能遇到更高的板,把“短板”换成更高的

反过来,如果右边矮,就动右边。就这么简单粗暴。

整个过程其实就是两个人从数组两头往中间挤,挤的过程中顺手算一下每次的面积,留住最大的那个。

用 Python 写一下,很短:

from typing import List

defmax_area(height: List[int]) -> int:
    left, right = 0, len(height) - 1
    ans = 0

while left < right:
        h = min(height[left], height[right])      # 当前这对木板的高度(短板)
        w = right - left                          # 宽度就是下标差
        area = h * w
if area > ans:
            ans = area

# 移动更矮的那一边,期待找到更高的短板
if height[left] < height[right]:
            left += 1
else:
            right -= 1

return ans

你看,跟刚才暴力那个比起来,这里只有一个 while,每一轮要么左指针往右挪,要么右指针往左挪,每次至少缩小 1 个间距,所以整个数组最多扫一遍就结束了:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1),就俩指针、几个变量

很多人会问:那我万一错过了某个组合怎么办? 比如有的组合是“先缩宽度,再涨高度”,感觉会不会被跳过去?

这个地方稍微严肃一点讲下直觉(不严谨证明那种):

  • 对于某个固定的宽度 w,你能得到的最大面积就是 w * (在这段区间内的最高短板)
  • 我们从最宽开始(两端),每次都把“短板”那一边往里挪 → 实际上是在尝试让短板越来越高
  • 对于每个可能的宽度,双指针这套走法都会给你一个“在这个宽度下较优的组合”,最终挑一个全局最大的

所以它不会漏掉“比当前答案更好”的那种情况(这里真正的严格证明网上有很多推导,就不在楼下讲数学证明了,困得脑壳疼)。

随便拿官方例子 height = [1,8,6,2,5,4,8,3,7] 打个小样子:

  • 一开始 (0, 8) → 高度 min(1,7)=1,宽度 8,面积 8
  • 左边太矮,没救,左指针右移
  • 变成 (1, 8) → 高度 min(8,7)=7,宽度 7,面积 49,瞬间起飞
  • 之后再怎么挪,都会算一遍面积,最后留下的就是最大那个

刷题的时候你可以自己在纸上画几根竖线看看,更直观一点。

我一般会多写一个小测试函数,方便本地随手测两下:

if __name__ == "__main__":
    arr = [1, 8, 6, 2, 5, 4, 8, 3, 7]
    print(max_area(arr))  # 正常输出 49

其实这道题挺适合用来练“思维转弯”的: 从“我把所有情况枚举一遍” → 到“我能不能用一点局部的贪心,把没希望的情况剪掉”。以后遇到那种“两个指针从两边往中间靠”的场景,多想想是不是也可以用类似的思路。

行了,不扯了,我得上去看下我们组那个小李的线上告警,他刚才跟我说又把配置写错了…