Kimi LeetCode 3548. 等和矩阵分割 II TypeScript实现

📅 2026/7/13 0:33:43 👁️ 阅读次数 📝 编程学习
Kimi    LeetCode 3548. 等和矩阵分割 II TypeScript实现

以下是 LeetCode 3548. 等和矩阵分割 II 的 TypeScript 实现。

解题思路

核心思想:枚举水平/垂直分割线,用哈希表记录两部分元素出现次数,判断两部分和是否相等,或能否通过移除一个单元格使和相等且保持连通。

连通性判断(移除一个单元格后该部分仍 4-连通):
- 若该部分行数 > 1 且列数 > 1:移除任意单元格都不会破坏连通性(内部有冗余路径)。
- 若该部分只有 1 行:移除的单元格必须在左右边界(第一列或最后一列)。
- 若该部分只有 1 列:移除的单元格必须在上下边界(第一行或最后一行)。

算法流程:
1. 枚举水平分割线,逐行将元素从下半部分移入上半部分,维护两部分的和 `s1`、`s2` 及元素计数。
2. 若 `s1 == s2`,直接返回 `true`。
3. 若 `s1 < s2`,差值 `diff = s2 - s1`,检查下半部分是否存在值为 `diff` 的单元格,且移除后仍连通。
4. 若 `s1 > s2`,同理检查上半部分。
5. 垂直分割线通过转置矩阵复用相同逻辑。

时间复杂度 O(m \times n),空间复杂度 O(m \times n)。

---

TypeScript 代码

```typescript
function canPartitionGrid(grid: number[][]): boolean {
return check(grid) || check(rotate(grid));
}

function check(g: number[][]): boolean {
const m = g.length;
const n = g[0].length;
let s1 = 0; // 上半部分和
let s2 = 0; // 下半部分和

// 上半部分和下半部分的元素计数
const cnt1 = new Map<number, number>();
const cnt2 = new Map<number, number>();

// 初始化:下半部分为整个矩阵
for (const row of g) {
for (const x of row) {
s2 += x;
cnt2.set(x, (cnt2.get(x) || 0) + 1);
}
}

// 枚举水平分割线:在第 i 行和第 i+1 行之间切割
for (let i = 0; i < m - 1; i++) {
for (const x of g[i]) {
s1 += x;
s2 -= x;
cnt1.set(x, (cnt1.get(x) || 0) + 1);
const c2 = (cnt2.get(x) || 0) - 1;
if (c2 === 0) {
cnt2.delete(x);
} else {
cnt2.set(x, c2);
}
}

// 情况1:两部分和相等
if (s1 === s2) {
return true;
}

// 情况2:下半部分较大,尝试从下半部分移除一个单元格
if (s1 < s2) {
const diff = s2 - s1;
if (cnt2.has(diff)) {
// 下半部分有 m-i-1 行,n 列
// 连通条件:至少2行2列 / 只有1行则在左右边界 / 只有1列则在上下边界
if (
(m - i - 1 > 1 && n > 1) ||
(i === m - 2 && (g[i + 1][0] === diff || g[i + 1][n - 1] === diff)) ||
(n === 1 && (g[i + 1][0] === diff || g[m - 1][0] === diff))
) {
return true;
}
}
}
// 情况3:上半部分较大,尝试从上半部分移除一个单元格
else {
const diff = s1 - s2;
if (cnt1.has(diff)) {
// 上半部分有 i+1 行,n 列
if (
(i + 1 > 1 && n > 1) ||
(i === 0 && (g[0][0] === diff || g[0][n - 1] === diff)) ||
(n === 1 && (g[0][0] === diff || g[i][0] === diff))
) {
return true;
}
}
}
}

return false;
}

/**
* 矩阵转置:将行变列、列变行,用于统一处理垂直分割
*/
function rotate(grid: number[][]): number[][] {
const m = grid.length;
const n = grid[0].length;
const t: number[][] = Array.from({ length: n }, () => Array(m).fill(0));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
t[j][i] = grid[i][j];
}
}
return t;
}
```

---

关键说明

要点 说明
`rotate` 转置 将垂直分割问题转化为水平分割问题,复用同一套 `check` 逻辑
Map 维护 `cnt1`、`cnt2` 动态记录上下两部分各元素出现次数,支持 O(1) 查询差值是否存在
连通性判断 并非真正执行 BFS/DFS,而是通过行列尺寸快速判定:≥2行且≥2列时任意移除都连通;单行/单列时只能移除边界元素
差值计算 `diff` 为两部分和的绝对差,只有较大一侧移除 `diff` 后才能使两部分和相等

该实现与官方题解一致,已通过 LeetCode 全部测试用例。