使矩阵中的 1 互不相邻的最小操作数
难度:
标签:
题目描述
代码结果
运行时间: 632 ms, 内存: 66.3 MB
/*
* 题目思路:
* 1. 使用 Java Stream 遍历矩阵,找到所有的 1 的位置。
* 2. 对每个 1 的位置,检查其上下左右是否有相邻的 1。
* 3. 计算每个 1 移动到非相邻位置所需的最小操作数。
* 4. 累计所有操作数,得到最终结果。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public int minOperations(int[][] grid) {
int n = grid.length;
int m = grid[0].length;
boolean[][] visited = new boolean[n][m];
List<int[]> ones = IntStream.range(0, n)
.boxed()
.flatMap(i -> IntStream.range(0, m)
.filter(j -> grid[i][j] == 1)
.mapToObj(j -> new int[]{i, j}))
.collect(Collectors.toList());
int operations = ones.stream()
.filter(pos -> !visited[pos[0]][pos[1]])
.mapToInt(pos -> bfs(grid, visited, pos[0], pos[1]))
.sum();
return operations;
}
private int bfs(int[][] grid, boolean[][] visited, int x, int y) {
int n = grid.length;
int m = grid[0].length;
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
int operations = 0;
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{x, y});
visited[x][y] = true;
while (!queue.isEmpty()) {
int[] pos = queue.poll();
int i = pos[0];
int j = pos[1];
for (int k = 0; k < 4; k++) {
int ni = i + dx[k];
int nj = j + dy[k];
if (ni >= 0 && ni < n && nj >= 0 && nj < m && grid[ni][nj] == 1 && !visited[ni][nj]) {
operations++;
visited[ni][nj] = true;
queue.add(new int[]{ni, nj});
}
}
}
return operations;
}
}
解释
方法:
这个题解使用图的最大匹配算法来解决问题。首先,将矩阵中的每个元素转换为图中的一个节点,节点的索引是通过行号和列号计算得到的。如果两个相邻的元素都是1,则在它们之间建立一条边。这样,原问题转化为找出图中的最大匹配,即最多的可以互不相邻的1对1的匹配。使用匈牙利算法(增广路径算法)来实现最大匹配。每次尝试找到一个未被匹配的节点,并尝试通过递归的方式进行匹配。如果可以匹配,增加匹配数,并递归尝试匹配更多节点。
时间复杂度:
O(V(V+E))
空间复杂度:
O(V+E)
代码细节讲解
🦆
为什么选择使用图的最大匹配算法来解决这个问题,有没有考虑过其他可能的算法?
▷🦆
在构建图的过程中,你是如何处理矩阵边界的?例如,如果一个元素位于矩阵的角落或边缘,你怎样确保不会访问到矩阵之外的元素?
▷🦆
匈牙利算法中,你如何确保每次尝试匹配的过程是高效的?有使用哪些特定的数据结构或优化方法来加速这一过程?
▷