forked from AnasImloul/Leetcode-Solutions
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathContain Virus.java
111 lines (89 loc) · 3.84 KB
/
Contain Virus.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
class Solution {
private static final int[][] DIR = new int[][]{
{1, 0}, {-1, 0}, {0, 1}, {0, -1}
};
public int containVirus(int[][] isInfected) {
int m = isInfected.length, n = isInfected[0].length;
int ans = 0;
while( true ) {
// infected regions, sorted desc according to the number of nearby
// uninfected nodes
PriorityQueue<Region> pq = new PriorityQueue<Region>();
// already visited cells
boolean[][] visited = new boolean[m][n];
// find regions
for(int i=0; i<m; i++) {
for(int j=0; j<n; j++) {
// if current cell is infected, and it's not visited
if( isInfected[i][j] != 1 || visited[i][j] )
continue;
// we found a new region, dfs to find all the infected
// and uninfected cells in the current region
Region reg = new Region();
dfs(i, j, reg, isInfected, visited, new boolean[m][n], m, n);
// if there are some uninfected nodes in this region,
// we can contain it, so add it to priority queue
if( reg.uninfected.size() != 0)
pq.offer(reg);
}
}
// if there are no regions to contain, break
if( pq.isEmpty() )
break;
// Contain region with most uninfected nodes
Region containReg = pq.poll();
ans += containReg.wallsRequired;
// use (2) to mark a cell as contained
for(int[] cell : containReg.infected)
isInfected[cell[0]][cell[1]] = 2;
// Spread infection to uninfected nodes in other regions
while( !pq.isEmpty() ) {
Region spreadReg = pq.poll();
for(int[] cell : spreadReg.uninfected)
isInfected[cell[0]][cell[1]] = 1;
}
}
return ans;
}
private void dfs(int i, int j, Region reg, int[][] grid, boolean[][] visited, boolean[][] uninfectedVis, int m, int n) {
visited[i][j] = true;
reg.addInfected(i, j);
for(int[] dir : DIR) {
int di = i + dir[0];
int dj = j + dir[1];
// continue, if out of bounds OR contained OR already visited
if( di < 0 || dj < 0 || di == m || dj == n || grid[di][dj] == 2 || visited[di][dj] )
continue;
// if neighbour node is not infected
if( grid[di][dj] == 0 ) {
// a wall will require to stop the spread from cell (i,j) to (di, dj)
reg.wallsRequired++;
// if this uninfected node is not already visited for current region
if( !uninfectedVis[di][dj] ) {
uninfectedVis[di][dj] = true;
reg.addUninfected(di, dj);
}
} else
dfs(di, dj, reg, grid, visited, uninfectedVis, m, n);
}
}
}
class Region implements Comparable<Region> {
public List<int[]> infected;
public List<int[]> uninfected;
public int wallsRequired;
public Region() {
infected = new ArrayList();
uninfected = new ArrayList();
}
public void addInfected(int row, int col) {
infected.add(new int[]{ row, col });
}
public void addUninfected(int row, int col) {
uninfected.add(new int[]{ row, col });
}
@Override
public int compareTo(Region r2) {
return Integer.compare(r2.uninfected.size(), uninfected.size());
}
}