33岁后端开发:今年找工作太难了,小厂觉得你待不久,中厂觉得你贵,大厂觉得你老
一个33岁的后端开发出来找工作,投了一圈之后发现,技术栈、项目经验先不聊,年龄和预期薪资已经先被人盘一遍了。
小公司一看你履历,心里嘀咕:这人是不是来了也待不住,给不起成长空间也留不住人。中型公司一算成本,又觉得你要价高,性价比不如招个年轻点的慢慢带。大厂那边更直接,简历扫到33岁,估计就开始怀疑你还有没有那么能熬。
这就很魔幻。你年轻的时候嫌你经验少,等你真干了几年,又嫌你老、嫌你贵、嫌你稳定性不好。打工人像是被卡在一个特别尴尬的位置,往前一步是成本,往后一步是淘汰。
HR看完可能也沉默,程序员看完血压已经上来了。33岁而已,怎么搞得像职场保质期快到了。
count([11,10]) 返回 1,换一批点返回 0,这题最容易写成“几何题”。
我第一眼不太信它是几何题。
题目叫「检测正方形」,但它检测的不是任意角度的正方形,而是边和 x、y 轴平行的正方形。这一点很关键。只要这个限制在,斜率、向量、两点距离,全都不用上。
题目大概是这样:
不断往系统里加点:
add([x, y])
然后给一个查询点:
count([x, y])
问:用这个查询点,再从已经添加过的点里选 3 个点,可以组成多少个正方形。
注意,点可以重复添加。重复点要按次数算。
这地方我一般不会先存一个点列表然后暴力扫三层。数据一大,基本就挂了。
更舒服的存法是:
(x, y) -> 出现次数
查询时只盯着和查询点在同一条竖线上的点。
比如查询点是 (x, y),如果另一个点是 (x, yy),那它们可以作为正方形的一条竖边。
边长就是:
side = yy - y
只要 side != 0,另外两个点只能在左边或者右边:
右边:
(x + side, y)
(x + side, yy)
左边:
(x - side, y)
(x - side, yy)
这就行了。
代码我会这么写,不搞花活:
from collections import defaultdict
classDetectSquares:
def__init__(self):
self.point_cnt = defaultdict(int)
self.same_x = defaultdict(list)
defadd(self, point):
x, y = point
key = (x, y)
if self.point_cnt[key] == 0:
self.same_x[x].append(y)
self.point_cnt[key] += 1
defcount(self, point):
x, y = point
ans = 0
for yy in self.same_x[x]:
if yy == y:
continue
side = yy - y
# 往右找一个正方形
right_bottom = (x + side, y)
right_top = (x + side, yy)
ans += (
self.point_cnt[(x, yy)]
* self.point_cnt[right_bottom]
* self.point_cnt[right_top]
)
# 往左找一个正方形
left_bottom = (x - side, y)
left_top = (x - side, yy)
ans += (
self.point_cnt[(x, yy)]
* self.point_cnt[left_bottom]
* self.point_cnt[left_top]
)
return ans
这里有个细节,same_x[x] 里我只放第一次出现的 y。
为什么?
因为重复点已经在 point_cnt 里记次数了。如果 same_x[x] 也重复塞,查询时会被多算一遍,这种 bug 很隐蔽,样例可能还过。
比如 (3, 10) 被 add 了两次,它应该影响的是组合数量:
self.point_cnt[(3, 10)] == 2
而不是循环两次。
这题真正要盯住的不是“正方形怎么判断”,而是“从查询点反推出另外三个点”。只要确定一条竖边,剩下两个点的位置就是死的。
复杂度也比较稳。
add 基本是 O(1)。
count 和当前查询点同 x 的不同 y 数量有关。实际写题的时候,这比扫所有点舒服太多。
我见过一种写法是枚举所有点,把它当成对角线点,然后去找另外两个点。也能做,但脑子要多转一下,还容易把边长正负写乱。
这题按竖边拆,判断顺序更像查表:
先找同 x 的点
再算边长
再查左右两个角
最后乘次数
写完自己拿一个小例子跑一下:
ds = DetectSquares()
ds.add([3, 10])
ds.add([11, 2])
ds.add([3, 2])
print(ds.count([11, 10])) # 1
ds.add([11, 2])
print(ds.count([11, 10])) # 2
第二次为什么是 2?
因为 (11, 2) 加了两次,同一个几何位置,但题目说重复点按次数算。很多人错就错在这里,直接用 set 存点,答案立刻少一截。
这题不用把它想复杂。
点可重复,用计数表。
正方形不旋转,用坐标差。
查询点固定,枚举同一竖线上的点。
剩下就是查三个哈希表位置。做到这里,代码基本就顺了。