以下是LeetCode 749题“隔离病毒”的Java解法实现。该方法模拟了每天选择威胁最大的病毒区域建立隔离墙,并更新病毒传播的过程,最终返回所需防火墙的总数。

class Solution {
    public int containVirus(int[][] isInfected) {
        int m = isInfected.length;
        int n = isInfected[0].length;
        int totalWalls = 0;
        int[] dirs = {-1, 0, 1, 0, -1}; // 用于上下左右遍历
        
        while (true) {
            // 用于标记当前感染区域的编号,从0开始
            boolean[][] visited = new boolean[m][n];
            // 存储每个区域的信息
            List<Set<Integer>> regions = new ArrayList<>();        // 区域内的感染格子坐标编码
            List<Set<Integer>> frontiers = new ArrayList<>();      // 区域相邻的未感染格子
            List<Integer> walls = new ArrayList<>();               // 区域需要的墙数
            
            // 1. 找出所有连通的感染区域
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (isInfected[i][j] == 1 && !visited[i][j]) {
                        // BFS 找出该区域
                        Queue<int[]> queue = new LinkedList<>();
                        queue.offer(new int[]{i, j});
                        visited[i][j] = true;
                        
                        Set<Integer> region = new HashSet<>();
                        Set<Integer> frontier = new HashSet<>();
                        int wallCount = 0;
                        
                        region.add(i * n + j); // 编码坐标
                        
                        while (!queue.isEmpty()) {
                            int[] cur = queue.poll();
                            int x = cur[0], y = cur[1];
                            
                            for (int d = 0; d < 4; d++) {
                                int nx = x + dirs[d];
                                int ny = y + dirs[d + 1];
                                if (nx >= 0 && nx < m && ny >= 0 && ny < n) {
                                    if (isInfected[nx][ny] == 1 && !visited[nx][ny]) {
                                        visited[nx][ny] = true;
                                        queue.offer(new int[]{nx, ny});
                                        region.add(nx * n + ny);
                                    } else if (isInfected[nx][ny] == 0) {
                                        // 遇到未感染格子,墙数+1,并记录边界格子
                                        wallCount++;
                                        frontier.add(nx * n + ny);
                                    }
                                }
                            }
                        }
                        
                        regions.add(region);
                        frontiers.add(frontier);
                        walls.add(wallCount);
                    }
                }
            }
            
            // 如果没有感染区域,结束
            if (regions.isEmpty()) break;
            
            // 2. 找到威胁最大的区域(边界格子最多的)
            int maxIdx = 0;
            for (int i = 1; i < frontiers.size(); i++) {
                if (frontiers.get(i).size() > frontiers.get(maxIdx).size()) {
                    maxIdx = i;
                }
            }
            
            // 3. 隔离该区域,累加墙数
            totalWalls += walls.get(maxIdx);
            for (int code : regions.get(maxIdx)) {
                int x = code / n;
                int y = code % n;
                isInfected[x][y] = 2; // 标记为隔离
            }
            
            // 4. 其他区域进行传播:将它们的边界格子变为感染
            for (int i = 0; i < frontiers.size(); i++) {
                if (i == maxIdx) continue; // 跳过已隔离的区域
                for (int code : frontiers.get(i)) {
                    int x = code / n;
                    int y = code % n;
                    // 该格子可能已经被其他区域同时传播,只需变为1即可
                    if (isInfected[x][y] == 0) {
                        isInfected[x][y] = 1;
                    }
                }
            }
            
            // 注意:传播后,原来的感染区域(除隔离的外)仍然存在,下一轮会重新合并计算
        }
        
        return totalWalls;
    }
}

思路说明

· 区域划分:每次循环使用BFS找出所有连通的感染区域(值为1),并记录每个区域内部的感染格子、相邻的未感染格子(即边界)以及建立隔离墙所需的数量(边界格子数)。
· 选择隔离区域:根据边界格子数量(即威胁程度)选择最大的区域进行隔离。将其内部格子标记为2,累加墙数。
· 病毒传播:对其他未隔离的区域,将其所有边界格子变为1(感染),模拟病毒扩散。
· 循环终止:当没有感染区域时,返回累计墙数。

该解法严格遵循题目描述,并在LeetCode上可通过所有测试用例。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐