裁员被召回
前段时间,我们说到了 理想裁员 18% 。
近日有爆料指出:理想开始召回部分被裁员员工,主要是测试端岗位的员工,召回原因是大裁员影响到了产品的研发测试。
首先,裁员 5% 就已经是重大组织变更了,现在裁员才过去没多久,就推翻之前的决策,说明当时这个裁员 18% 决策做得过于草率。
更加魔幻的是,那些被召回的员工,有些还没收到裁员的大礼包呢,结果现在却收到了被召回的通知 🤣🤣🤣
针对被裁召回,理想方面给出的方案是:
- 如果召回员工的大礼包已发放,那么需要退回
- 如果召回员工的大礼包尚未发放,那么不给了
所有召回员工的合同直接延续,这段时间的休假白给。
后面两条规则没意见,但是大礼包处理这个实在魔幻。
一个比较折中且合理的做法:统一一个退回比例,而非直接全退(或直接不发放)。
我猜测理想方面觉得,这段时间的假期白送本身就已经是对员工的"补偿让利"。
但有正常思考能力的人,都不难猜测到:会考虑召回的那么这些员工,大概率还没找到称心的工作,这段所谓的"休假"是绝对的煎熬。
这些经历,怎么能作为对员工的补偿让利呢?
新闻看多了,真就觉得世界是个巨大的草台班子。
...
回归主线。
来一道热乎的「字节跳动(校招)」相关的题目。
题目描述
平台:LeetCode
题号:827
给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。
返回执行此操作后,grid 中最大的岛屿面积是多少?
岛屿 由一组上、下、左、右四个方向相连的 1 形成。
示例 1:
输入: grid = [[1, 0], [0, 1]]
输出: 3
解释: 将一格0变成1,最终连通两个小岛得到面积为 3 的岛屿。
示例 2:
输入: grid = [[1, 1], [1, 0]]
输出: 4
解释: 将一格0变成1,岛屿的面积扩大为 4。
示例 3:
输入: grid = [[1, 1], [1, 1]]
输出: 4
解释: 没有0可以让我们变成1,面积依然为 4。
提示:
grid[i][j]为0或1
并查集 + 枚举
为了方便,我们令 grid 为 g。
根据题意,容易想到通过「并查集」来维护所有连通块大小,再通过「枚举」来找最优翻转点。
具体的,我们可以先使用「并查集」维护所有 的块连通性,并在维护连通性的过程中,使用 sz[idx] 记录下每个连通块的大小(注意:只有连通块根编号,sz[idx] 才有意义,即只有 sz[find(x)] 才有意义)。
随后我们再次遍历 g,根据原始的 的值进行分别处理:
- 若 ,该位置不会作为翻转点,但真实最大面积未必是由翻转后所导致的(可能取自原有的连通块),因此我们需要将 参与比较,其中
root为 所属的连通块根节点编号; - 若 ,该位置可作为翻转点,我们可以统计其四联通位置对应的连通块大小总和
tot(注意若四联通方向有相同连通块,只统计一次),那么 即是翻转该位置所得到的新连通块大小。
最后对所有连通块大小取最大值即是答案。
一些细节:为了方便,我们令点 的编号从 开始; 同时由于我们本身就要用
sz数组,因此我们可以随手把并查集的「按秩合并」也加上。体现在union操作时,我们总是将小的连通块合并到大的连通块上,从而确保我们并查集单次操作即使在最坏情况下复杂度仍为 (可看作常数)。需要注意只有同时应用「路径压缩」和「按秩合并」,并查集操作复杂度才为 。
Java 代码:
class Solution {
static int N = 510;
static int[] p = new int[N * N], sz = new int[N * N];
int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void union(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return ;
if (sz[ra] > sz[rb]) {
union(b, a);
} else {
sz[rb] += sz[ra]; p[ra] = p[rb];
}
}
public int largestIsland(int[][] g) {
int n = g.length;
for (int i = 1; i <= n * n; i++) {
p[i] = i; sz[i] = 1;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (g[i][j] == 0) continue;
for (int[] di : dirs) {
int x = i + di[0], y = j + di[1];
if (x < 0 || x >= n || y < 0 || y >= n || g[x][y] == 0) continue;
union(i * n + j + 1, x * n + y + 1);
}
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (g[i][j] == 1) {
ans = Math.max(ans, sz[find(i * n + j + 1)]);
} else {
int tot = 1;
Set<Integer> set = new HashSet<>();
for (int[] di : dirs) {
int x = i + di[0],y = j + di[1];
if (x < 0 || x >= n || y < 0 || y >= n || g[x][y] == 0) continue;
int root = find(x * n + y + 1);
if (set.contains(root)) continue;
tot += sz[root];
set.add(root);
}
ans = Math.max(ans, tot);
}
}
}
return ans;
}
}
C++ 代码:
class Solution {
public:
int p[510 * 510], sz[510 * 510];
vector<vector<int>> dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void unionX(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return;
if (sz[ra] > sz[rb]) {
unionX(b, a);
} else {
sz[rb] += sz[ra];
p[ra] = p[rb];
}
}
int largestIsland(vector<vector<int>>& g) {
int n = g.size();
for (int i = 1; i <= n * n; i++) {
p[i] = i; sz[i] = 1;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (g[i][j] == 0) continue;
for (const auto& di : dirs) {
int x = i + di[0], y = j + di[1];
if (x < 0 || x >= n || y < 0 || y >= n || g[x][y] == 0) continue;
unionX(i * n + j + 1, x * n + y + 1);
}
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (g[i][j] == 1) {
ans = max(ans, sz[find(i * n + j + 1)]);
} else {
int tot = 1;
unordered_set<int> set;
for (const auto& di : dirs) {
int x = i + di[0], y = j + di[1];
if (x < 0 || x >= n || y < 0 || y >= n || g[x][y] == 0) continue;
int root = find(x * n + y + 1);
if (set.find(root) != set.end()) continue;
tot += sz[root];
set.insert(root);
}
ans = max(ans, tot);
}
}
}
return ans;
}
};
Python 代码:
class Solution:
def find(self, p, x):
if p[x] != x:
p[x] = self.find(p, p[x])
return p[x]
def union(self, p, sz, a, b):
ra, rb = self.find(p, a), self.find(p, b)
if ra == rb:
return
if sz[ra] > sz[rb]:
ra, rb = rb, ra
sz[rb] += sz[ra]
p[ra] = p[rb]
def largestIsland(self, g: List[List[int]]) -> int:
n, ans = len(g), 0
p, sz = [i for i in range(n * n + 10)], [1 for _ in range(n * n + 10)]
dirs = [[1,0],[-1,0],[0,1],[0,-1]]
for i in range(n):
for j in range(n):
if g[i][j] == 0:
continue
for di in dirs:
x, y = i + di[0], j + di[1]
if x < 0 or x >= n or y < 0 or y >= n or g[x][y] == 0:
continue
self.union(p, sz, i * n + j + 1, x * n + y + 1)
for i in range(n):
for j in range(n):
if g[i][j] == 1:
ans = max(ans, sz[self.find(p, i * n + j + 1)])
else:
tot = 1
vis = set()
for di in dirs:
x, y = i + di[0], j + di[1]
if x < 0 or x >= n or y < 0 or y >= n or g[x][y] == 0:
continue
root = self.find(p, x * n + y + 1)
if root in vis:
continue
tot += sz[root]
vis.add(root)
ans = max(ans, tot)
return ans
TypeScript 代码:
const N = 510
const p = new Array<number>(N * N).fill(-1), sz = new Array<number>(N * N).fill(1)
const dirs = [[1,0], [-1,0], [0,1], [0,-1]]
function find(x: number): number {
if (p[x] != x) p[x] = find(p[x])
return p[x]
}
function union(a: number, b: number): void {
const ra = find(a), rb = find(b)
if (ra == rb) return
if (sz[ra] > sz[rb]) {
union(rb, ra)
} else {
sz[rb] += sz[ra]; p[ra] = p[rb]
}
}
function largestIsland(g: number[][]): number {
const n = g.length
for (let i = 1; i <= n * n; i++) {
p[i] = i; sz[i] = 1
}
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (g[i][j] == 0) continue
for (const di of dirs) {
const x = i + di[0], y = j + di[1]
if (x < 0 || x >= n || y < 0 || y >= n || g[x][y] == 0) continue
union(i * n + j + 1, x * n + y + 1)
}
}
}
let ans = 0
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
if (g[i][j] == 1) {
ans = Math.max(ans, sz[find(i * n + j + 1)])
} else {
let tot = 1
const set = new Set()
for (let di of dirs) {
const x = i + di[0], y = j + di[1]
if (x < 0 || x >= n || y < 0 || y >= n || g[x][y] == 0) continue
const root = find(x * n + y + 1)
if (set.has(root)) continue
tot += sz[root]
set.add(root)
}
ans = Math.max(ans, tot)
}
}
}
return ans
};
- 时间复杂度:
- 空间复杂度: