某大厂员工:有个很菜的同事,去了体制内像他这样有学历没技术的,去体制内,是最不浪费个人优势的,能完美避开自己的短处!
一个大厂员工吐槽,说身边有个同事技术挺菜,代码写得磕磕巴巴,排查问题也经常靠别人兜底,但人家最后去了体制内。
还说去体制内,是最不浪费个人优势的,能完美避开自己的短处!
你别说,体制内很多岗位拼的未必是你框架多熟、性能调优多猛,而是稳不稳、会不会写材料、能不能按流程办事。这样一看,有学历没技术的人去那里,好像还真不是躲,是把自己的短板藏起来,把长板摆到台面上。
最搞的是,留在大厂的人还在半夜改bug,人家可能已经开始研究怎么把周报写得更像周报了,想想也挺魔幻。
面试题:砖墙
砖墙这题,最容易写歪的地方是去“画线”。
一看题目说从上往下画一条竖线,很多人第一反应就是模拟墙的每一列,看这条线穿过几块砖。这个方向我一般直接不信。砖宽可能很大,真按坐标一格一格扫,代码看着勤快,实际就是在给自己挖坑。
这题真正要看的,不是线穿过了多少块砖,而是线有没有刚好卡在砖缝上。
比如一行砖是:
[1, 2, 2, 1]
从左往右算砖缝位置:
1, 3, 5
注意最后那个墙的右边界不能算。题目不允许线贴着墙边画,不然直接一条线从最右边下去,穿过 0 块砖,这题就没意义了。
所以每一行只需要统计“内部砖缝”的位置。哪一个位置出现次数最多,说明竖线画在这里,能避开的砖最多。
最后答案就是:
总行数 - 出现次数最多的砖缝数
这地方有个坑,别把“砖块宽度”当成 key,key 应该是“前缀和位置”。
我会这么写:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
publicclassBrickWallCounter{
publicintleastBricks(List<List<Integer>> wall){
Map<Integer, Integer> gapCount = new HashMap<>();
int bestGap = 0;
for (List<Integer> row : wall) {
int pos = 0;
// 最后一块砖的右边界不能统计,所以只扫到 size - 1
for (int i = 0; i < row.size() - 1; i++) {
pos += row.get(i);
int times = gapCount.getOrDefault(pos, 0) + 1;
gapCount.put(pos, times);
if (times > bestGap) {
bestGap = times;
}
}
}
return wall.size() - bestGap;
}
}
这段代码里我最在意的是这个循环边界:
for (int i = 0; i < row.size() - 1; i++)
这比后面再判断“是不是最后一个位置”要干净。很多 bug 就是从多算了墙的最右边界开始的。尤其是测试样例比较弱的时候,你还以为自己过了,换一组全是单块砖的墙,结果就露馅了。
比如:
[
[3],
[3],
[3]
]
每一行都没有内部砖缝。这个时候 gapCount 为空,bestGap 还是 0,结果就是 3。
意思也对:你不管怎么画,都会穿过 3 块砖。
再看一个稍微正常点的:
[
[1, 2, 2, 1],
[3, 1, 2],
[1, 3, 2],
[2, 4],
[3, 1, 2],
[1, 3, 1, 1]
]
内部砖缝位置大概会被统计成这样:
位置 1:出现 3 次
位置 2:出现 1 次
位置 3:出现 3 次
位置 4:出现 4 次
位置 5:出现 2 次
最多的是位置 4,出现了 4 次。总共有 6 行,所以最少穿过:
6 - 4 = 2
这题的复杂度也比较舒服。每块砖最多扫一次,时间复杂度是 O(n),这里的 n 是所有砖块数量。空间复杂度取决于不同砖缝位置的数量,最坏也是 O(n)。
这类题别急着模拟过程。题目让你画线,不代表代码里真要画线。线只是表象,真正能减少穿砖数的,是每一行砖缝重合的位置。
把这个位置数清楚,题就结束了。