https://leetcode.com/problems/contain-virus/
https://leetcode.com/articles/contain-virus/
https://leetcode.com/problems/contain-virus/discuss/110174/My-Neat-Java-Solution-Using-Dfs
X. Videos
花花酱 LeetCode 749. Contain Virus - 刷题找工作 EP136
A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls.
The world is modeled as a 2-D array of cells, where
0
represents uninfected cells, and 1
represents cells contaminated with the virus. A wall (and only one wall) can be installed between any two 4-directionally adjacent cells, on the shared boundary.
Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. Resources are limited. Each day, you can install walls around only one region -- the affected area (continuous block of infected cells) that threatens the most uninfected cells the following night. There will never be a tie.
Can you save the day? If so, what is the number of walls required? If not, and the world becomes fully infected, return the number of walls used.
Example 1:
Input: grid = [[0,1,0,0,0,0,0,1], [0,1,0,0,0,0,0,1], [0,0,0,0,0,0,0,1], [0,0,0,0,0,0,0,0]] Output: 10 Explanation: There are 2 contaminated regions. On the first day, add 5 walls to quarantine the viral region on the left. The board after the virus spreads is: [[0,1,0,0,0,0,1,1], [0,1,0,0,0,0,1,1], [0,0,0,0,0,0,1,1], [0,0,0,0,0,0,0,1]] On the second day, add 5 walls to quarantine the viral region on the right. The virus is fully contained.
Example 2:
Input: grid = [[1,1,1], [1,0,1], [1,1,1]] Output: 4 Explanation: Even though there is only one cell saved, there are 4 walls built. Notice that walls are only built on the shared boundary of two different cells.
Example 3:
Input: grid = [[1,1,1,0,0,0,0,0,0], [1,0,1,0,1,1,1,1,1], [1,1,1,0,0,0,0,0,0]] Output: 13 Explanation: The region on the left only builds two new walls.
Note:
- The number of rows and columns of
grid
will each be in the range[1, 50]
. - Each
grid[i][j]
will be either0
or1
. - Throughout the described process, there is always a contiguous viral region that will infect strictly more uncontaminated squares in the next round
这道题给了我们一个由0和1组成的二维数组,其中0表示健康细胞,而1表示病毒细胞,多个相邻的1组成了病毒细胞群,每天都会向周围扩散一圈,除非我们在其跟健康细胞之间建立隔离墙,这样其才会不会扩散。我们每天只能给一个病毒细胞群来建立隔离墙,其他的细胞群会进行扩散。问最终我们需要多少个隔离墙。这道题真的挺难,博主研究了好久才弄明白题目的意思。
首先要明白一点,病毒细胞只会向上下左右四个方向相邻的健康细胞扩散。需要注意的一点是,需要的隔离墙的数量可能大于周围相邻的健康细胞,最明显的就是例子2中,只有一个健康细胞,但是需要四个隔离墙才能保护这个健康细胞不被感染。还有就是,我们需要隔离某个病毒细胞群的判定依据是其能感染的健康细胞的数量,而不是需要建的墙的数量或者病毒细胞的个数,这点很重要,博主之前没有注意这一点,导致fail了一个test case。所以我们要做的就是要求出每个病毒细胞群能感染的健康细胞的数量,其周围能建墙的地方,以及每个病毒细胞的位置。我们再其中选择能感染最多健康细胞的病毒细胞群进行建墙,建完墙后,我们将该群中的所有病毒细胞标记为-1,跟其他细胞区分出来。对于其他所有的病毒细胞群,将其周围能建墙的地方(即健康细胞)都标记为1,表示其现在已经被感染成了病毒细胞。然后再进行新的一轮循环检测,直到无法找出新的病毒细胞为止。
我们先找值为1的点,找到后,以其作为起点,进行BFS遍历,将和其相连的所有为1的点都找出来,在BFS遍历的过程中,如果我们检测到周围位置值为0,将其加入walls数组,表示这里可以建隔离墙,如果检测到周围位置为1,将其加入virus数组,表示这里是病毒细胞,注意起始位置也要提前加入virus数组。我们这里为了节省维度,将二维的坐标都encode成了一个int数字。BFS遍历结束后,我们根据walls数组来算出能感染的健康细胞的个数,因为我们前面提到过建隔离墙的位置可能大于健康细胞的个数,所以我们只要去除wall数组的重复项即可,利用HashSet的去重复项原理,然后将剩下的个数放入cells数组中。把cells,walls,和virus数组放入一个vector中,表示一个病毒细胞群的信息,再放入一个大数组all中,这样我们收集了所有病毒细胞群的信息后,可以根据可感染的健康细胞个数由多到少来排序,这样我们就把第一个病毒细胞群中所有virus数组的位置值变为-1,并且把可感染的健康细胞个数累加到结果res中。然后把后面所有的病毒细胞群中walls的位置值都变为1即可。当all数组为空时,跳出循环,表示没有检测到病毒细胞群或者全部都被感染了
这是一道比较繁琐的DFS题目,我们将题目的求解分为如下几个步骤:1)遍历各个细菌群,找出下一步受感染最多的一个细菌群;2)将这个群里的细菌用墙隔离起来(实现中就是将cells的值置为-1);3)模拟其余细菌群的扩展过程,修改cells的值。重复上面3个步骤,直到找不出需要进一步隔离的细菌群即可
此题实际上是一个模拟+贪心,首先可以简单计算每次感染后得到的边界大小。优先选择感染边界最大的,这样可以减少后续的感染人数。接下来,只需要确定每次感染后的图像,根据这些图像重新一轮计算,直到没有新的区域产生。
用到DFS寻找病毒群,BFS模拟冰毒传播
https://leetcode.com/articles/contain-virus/
Let's work on simulating one turn of the process. We can repeat this as necessary while there are still infected regions.
Algorithm
Though the implementation is long, the algorithm is straightforward. We perform the following steps:
- Find all viral regions (connected components), additionally for each region keeping track of the frontier (neighboring uncontaminated cells), and the perimeter of the region.
- Disinfect the most viral region, adding it's perimeter to the answer.
- Spread the virus in the remaining regions outward by 1 square.
- Time Complexity: ) where is the number of rows and columns. After time , viral regions that are alive must have size at least , so the total number removed across all time is .
- Space Complexity: in additional space.
Set<Integer> seen;
List<Set<Integer>> regions;
List<Set<Integer>> frontiers;
List<Integer> perimeters;
int[][] grid;
int R, C;
int[] dr = new int[] { -1, 1, 0, 0 };
int[] dc = new int[] { 0, 0, -1, 1 };
public int containVirus(int[][] grid) {
this.grid = grid;
R = grid.length;
C = grid[0].length;
int ans = 0;
while (true) {
seen = new HashSet();
regions = new ArrayList();
frontiers = new ArrayList();
perimeters = new ArrayList();
for (int r = 0; r < R; ++r) {
for (int c = 0; c < C; ++c) {
if (grid[r][c] == 1 && !seen.contains(r * C + c)) {
regions.add(new HashSet());
frontiers.add(new HashSet());
perimeters.add(0);
dfs(r, c);
}
}
}
if (regions.isEmpty())
break;
int triageIndex = 0;
for (int i = 0; i < frontiers.size(); ++i) {
if (frontiers.get(triageIndex).size() < frontiers.get(i).size())
triageIndex = i;
}
ans += perimeters.get(triageIndex);
for (int i = 0; i < regions.size(); ++i) {
if (i == triageIndex) {
for (int code : regions.get(i))
grid[code / C][code % C] = -1;
} else {
for (int code : regions.get(i)) {
int r = code / C, c = code % C;
for (int k = 0; k < 4; ++k) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < R && nc >= 0 && nc < C && grid[nr][nc] == 0)
grid[nr][nc] = 1;
}
}
}
}
}
return ans;
}
public void dfs(int r, int c) {
if (!seen.contains(r*C + c)) {
seen.add(r*C + c);
int N = regions.size();
regions.get(N - 1).add(r*C + c);
for (int k = 0; k < 4; ++k) {
int nr = r + dr[k], nc = c + dc[k];
if (nr >= 0 && nr < R && nc >= 0 && nc < C) {
if (grid[nr][nc] == 1) {
dfs(nr, nc);
} else if (grid[nr][nc] == 0){
frontiers.get(N - 1).add(nr*C + nc);
perimeters.set(N - 1, perimeters.get(N - 1) + 1);
}
}
}
}
}
https://leetcode.com/problems/contain-virus/discuss/110174/My-Neat-Java-Solution-Using-Dfs
X. Videos
花花酱 LeetCode 749. Contain Virus - 刷题找工作 EP136