前某节HR:现在面试最怕遇到一上来就卑微到骨子里的候选人,工资不敢问,加班不敢提,说啥他都点头,恨不得把姿态踩到地底下去讨好
前某节HR那句吐槽我是真信。面试最怕啥?不是嘴硬的,是那种一坐下就先把自己气场砍半截的人。工资不敢问,双休不敢提,加班含糊两句他就疯狂点头,像不是来找工作,是来求个收留。HR看着都别扭,因为你越这样,对面越默认你好拿捏。
评论区也挺损。有人说,这种不是谦虚,是提前把自己卖便宜了。还有人讲得更直接:你连自己都不替自己争,谁会替你争。
职场这地方,本来就是谈条件的。你有活,他有坑,坐下来就是互相看看合不合适。结果有人上来先把膝盖交出去,那后面工资低、活又杂、边界全没了,基本也别意外。面试时态度可以正常,真没必要把自己聊成“随时待命型耗材”。
面试题:隔离病毒
一上来先别想着怎么扩散,先想怎么堵。
这题叫“隔离病毒”,乍一看像模拟,真写起来最容易死在两个地方:一个是区域怎么找,另一个是墙到底该给谁修。很多人第一反应是“发现一个感染块就先围起来”,这思路不太稳。因为题目不是让你把所有病毒都处理掉,而是每一轮只隔离那个明天危害最大的区域。这个判断顺序一错,后面全乱。
我做这题时,第一眼就不太信那种边扫边改 grid 的写法。现场改感染状态,特别容易把这一轮和下一轮的状态搅一起。稳一点的做法还是分三步:
先把当前所有感染区域找出来; 再分别算每个区域能感染多少个未感染格子,以及需要多少堵墙; 最后只封禁威胁最大的那个区域,其它区域继续扩散。
这题本质上不是 DFS 难,而是状态管理烦。
先看核心数据结构,别上来就写一大坨:
classRegion{
List<int[]> cells = new ArrayList<>();
Set<Integer> frontier = new HashSet<>(); // 下一轮能感染到的点
int walls;
}
这里 cells 存当前病毒块,frontier 存它能威胁到的 0,walls 存为围住它需要的墙数。 注意,frontier.size() 才是我们选“优先封谁”的依据,不是 cells.size()。有些块看着大,其实周围早没地方可扩了,价值不高。
区域扫描我一般这么写,够短,也不容易绕晕:
privatevoiddfs(int[][] grid, int x, int y, boolean[][] seen, Region region){
int m = grid.length, n = grid[0].length;
if (x < 0 || x >= m || y < 0 || y >= n || seen[x][y] || grid[x][y] != 1) {
return;
}
seen[x][y] = true;
region.cells.add(newint[]{x, y});
int[] dx = {1, -1, 0, 0};
int[] dy = {0, 0, 1, -1};
for (int k = 0; k < 4; k++) {
int nx = x + dx[k], ny = y + dy[k];
if (nx < 0 || nx >= m || ny < 0 || ny >= n) {
continue;
}
if (grid[nx][ny] == 1) {
dfs(grid, nx, ny, seen, region);
} elseif (grid[nx][ny] == 0) {
region.walls++;
region.frontier.add(nx * n + ny);
}
}
}
这里有个细节很关键:墙数要按边算,frontier 去重只为了统计威胁面积,不能拿去重后的数量代替墙数。
比如一个未感染格子,可能同时和这个区域的两块病毒相邻,那它只算一个待感染点,但墙得修两段。这个地方写错的人很多,样例都过不干净。
主流程就清楚了,每轮做一次决策:
publicintcontainVirus(int[][] grid){
int m = grid.length, n = grid[0].length;
int ans = 0;
while (true) {
boolean[][] seen = newboolean[m][n];
List<Region> regions = new ArrayList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1 && !seen[i][j]) {
Region region = new Region();
dfs(grid, i, j, seen, region);
regions.add(region);
}
}
}
if (regions.isEmpty()) break;
int idx = -1, maxFrontier = 0;
for (int i = 0; i < regions.size(); i++) {
if (regions.get(i).frontier.size() > maxFrontier) {
maxFrontier = regions.get(i).frontier.size();
idx = i;
}
}
if (maxFrontier == 0) break;
ans += regions.get(idx).walls;
for (int i = 0; i < regions.size(); i++) {
Region r = regions.get(i);
if (i == idx) {
for (int[] cell : r.cells) {
grid[cell[0]][cell[1]] = 2; // 已隔离
}
} else {
for (int code : r.frontier) {
grid[code / n][code % n] = 1;
}
}
}
}
return ans;
}
这里把被隔离的区域标成 2,这个习惯挺重要。别还用 1,不然后面 DFS 又把它当活病毒块扫进去了,等于白围。