程序员老鬼

某大厂hr:裁完11位员工后,我也被优化了~

有网友吐槽,去年作为某大厂的HR,承担了裁员的任务,要在月底前完成11位员工的优化工作。那段时间,我每天都在和员工们进行艰难的对话。、

尽管如此,还是按照老板的要求,严格执行了裁员方案,把赔偿压到最低,并且对每个人的n+1方案都进行了详细计算,尽可能减少公司的支出。

Image

然而,没想到的是,今年3月,自己也成了被优化的对象。

作为HR,常常是站在执行者的位置,帮助公司做出决策,然而当这个决策降临到自己身上时,才深刻感受到那种无助和失落。曾经处理过无数个告别的场面,现在却轮到自己站在那一边,这种感觉真的是很复杂。

任何岗位和身份的变化,都是瞬息万变的,我们每个人都可能会面临被优化的一天。

面试题:岛屿数量

并查集也能做“岛屿数量”,但我真正在面试里看这题,第一反应一般还是 DFS。不是因为它多高级,恰恰是因为它直,代码短,排查起来也省心。给你一张 grid,里面 1 是陆地,0 是海水,问一共有多少块互相连着的陆地,本质上就是:找到一块陆地,把和它连成一片的都淹掉,然后继续往后扫。这个路子,写起来不绕。整体表达上我参考了你给的几篇技术文那种“直接进问题、少铺垫、靠代码说话”的感觉,但下面代码和组织都是我重新写的。

先看核心代码:

publicclassIslandCounter{

publicintnumIslands(char[][] grid){
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return0;
        }

int rows = grid.length;
int cols = grid[0].length;
int count = 0;

for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1') {
                    count++;
                    flood(grid, r, c, rows, cols);
                }
            }
        }
return count;
    }

privatevoidflood(char[][] grid, int r, int c, int rows, int cols){
if (r < 0 || r >= rows || c < 0 || c >= cols) {
return;
        }
if (grid[r][c] != '1') {
return;
        }

        grid[r][c] = '0';

        flood(grid, r + 1, c, rows, cols);
        flood(grid, r - 1, c, rows, cols);
        flood(grid, r, c + 1, rows, cols);
        flood(grid, r, c - 1, rows, cols);
    }
}

这段代码有个很实在的点:不额外开 visited 数组,直接把访问过的陆地改成 0。面试里这么写,通常比你又开一个布尔矩阵更利索。当然,前提是题目允许你改原数组。要是不让改,那就老老实实补个 visited。

思路其实就两步。

第一步,双层循环把整个矩阵扫一遍。只要碰到 1,说明发现了一座新岛,计数器先加一。

第二步,从这个点出发做 DFS,把上下左右所有相连的 1 全部清掉。这样后面再扫到这些位置时,就不会重复计数了。

举个很小的例子:

char[][] grid = {
    {'1','1','0','0'},
    {'1','0','0','1'},
    {'0','0','1','1'},
    {'0','0','0','0'}
};

左上角那一片算一座,右边连着的那一片算一座,所以结果是 2。

这题时间复杂度是 O(m * n),因为每个格子最多访问一次。空间复杂度表面看没开额外数组,但递归栈还在,最坏情况下是 O(m * n)。这地方面试官真要抠细节,别只会背“空间复杂度 O(1)”,那就有点悬。

还有个坑我顺手提一句:数据特别大时,递归可能会有栈深问题。线上真碰到超大矩阵,我未必会死磕递归,可能直接换成队列做 BFS,更稳一点。