leetcode
leetcode 1851 ~ 1900
使矩阵中的 1 互不相邻的最小操作数

使矩阵中的 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)

代码细节讲解

🦆
为什么选择使用图的最大匹配算法来解决这个问题,有没有考虑过其他可能的算法?
图的最大匹配算法适用于这个问题是因为我们需要找到最大数量的互不相邻的1对来消除。这可以被视为一个典型的图匹配问题,其中每个1代表一个节点,相邻的1之间有边连接。尽管可以考虑使用动态规划或贪心算法,但这些方法在处理节点之间复杂关系的情况下通常效果不佳或难以实现。最大匹配算法提供了一个精确的方法来确定最多的不相交对,这是处理此类问题的标准方法之一。
🦆
在构建图的过程中,你是如何处理矩阵边界的?例如,如果一个元素位于矩阵的角落或边缘,你怎样确保不会访问到矩阵之外的元素?
在构建图的过程中,我通过在添加边之前检查索引的合法性来处理矩阵边界。例如,当检查一个元素的上方相邻元素是否为1时,我会先判断这个元素是否在第一行;类似地,检查左侧元素时,会判断是否在第一列。这样通过条件判断确保不会访问到矩阵之外的元素,避免了数组越界的错误。
🦆
匈牙利算法中,你如何确保每次尝试匹配的过程是高效的?有使用哪些特定的数据结构或优化方法来加速这一过程?
在使用匈牙利算法进行匹配时,我通过使用递归函数和访问标记来确保过程的高效性。特别地,利用一个集合来记录已访问过的节点,以避免重复处理和陷入无限循环。每次尝试匹配前,会清空访问标记集合,保证每次搜索的独立性。此外,使用字典来存储节点间的连接关系和当前的匹配状态,使得查找和更新操作都能在常数时间内完成。这些数据结构的选择和使用大大提高了算法的效率和实现的简洁性。

相关问题