LeetCode Solutions
749. Contain Virus
Time: $O(m^2n^2)$ Space: $O(mn)$
struct Region {
// Given m = # of rows and n = # of cols, (x, y) will be hashed as x * n + y
unordered_set<int> infected;
unordered_set<int> noninfected; // Noninfected neighbors
int wallsRequired = 0;
};
class Solution {
public:
int containVirus(vector<vector<int>>& grid) {
const int m = grid.size();
const int n = grid[0].size();
int ans = 0;
while (true) {
vector<Region> regions;
vector<vector<bool>> seen(m, vector<bool>(n));
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if (grid[i][j] == 1 && !seen[i][j]) {
Region region;
dfs(grid, i, j, region, seen); // Use DFS to find all regions (1s)
if (!region.noninfected.empty())
regions.push_back(region);
}
if (regions.empty())
break; // No region causes further infection
// Region which infects most neighbors is in the back
sort(begin(regions), end(regions), [](const auto& a, const auto& b) {
return a.noninfected.size() < b.noninfected.size();
});
// Build walls around the region which infects most neighbors
Region mostInfectedRegion = regions.back();
regions.pop_back();
ans += mostInfectedRegion.wallsRequired;
for (const int neighbor : mostInfectedRegion.infected) {
const int i = neighbor / n;
const int j = neighbor % n;
// The grid is now contained and won't be infected anymore
grid[i][j] = 2;
}
// For remaining regions, expand (infect their neighbors)
for (const Region& region : regions)
for (const int neighbor : region.noninfected) {
const int i = neighbor / n;
const int j = neighbor % n;
grid[i][j] = 1;
}
}
return ans;
}
private:
void dfs(const vector<vector<int>>& grid, int i, int j, Region& region,
vector<vector<bool>>& seen) {
if (i < 0 || i == grid.size() || j < 0 || j == grid[0].size())
return;
if (seen[i][j] || grid[i][j] == 2)
return;
if (grid[i][j] == 0) {
region.noninfected.insert(i * grid[0].size() + j);
++region.wallsRequired;
return;
}
// grid[i][j] == 1
seen[i][j] = true;
region.infected.insert(i * grid[0].size() + j);
dfs(grid, i + 1, j, region, seen);
dfs(grid, i - 1, j, region, seen);
dfs(grid, i, j + 1, region, seen);
dfs(grid, i, j - 1, region, seen);
}
};
class Region {
// Given m = # of rows and n = # of cols, (x, y) will be hashed as x * n + y
public Set<Integer> infected = new HashSet<>();
public Set<Integer> noninfected = new HashSet<>(); // Noninfected neighbors
public int wallsRequired = 0;
};
class Solution {
public int containVirus(int[][] grid) {
final int m = grid.length;
final int n = grid[0].length;
int ans = 0;
while (true) {
List<Region> regions = new ArrayList<>();
boolean[][] seen = new boolean[m][n];
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
if (grid[i][j] == 1 && !seen[i][j]) {
Region region = new Region();
dfs(grid, i, j, region, seen); // Use DFS to find all regions (1s)
if (!region.noninfected.isEmpty())
regions.add(region);
}
if (regions.isEmpty())
break; // No region causes further infection
// Region which infects most neighbors is in the back
Collections.sort(regions, (a, b) -> a.noninfected.size() - b.noninfected.size());
// Build walls around the region which infects most neighbors
Region mostInfectedRegion = regions.get(regions.size() - 1);
regions.remove(regions.size() - 1);
ans += mostInfectedRegion.wallsRequired;
for (final int neighbor : mostInfectedRegion.infected) {
final int i = neighbor / n;
final int j = neighbor % n;
// The grid is now contained and won't be infected anymore
grid[i][j] = 2;
}
// For remaining regions, expand (infect their neighbors)
for (final Region region : regions)
for (final int neighbor : region.noninfected) {
final int i = neighbor / n;
final int j = neighbor % n;
grid[i][j] = 1;
}
}
return ans;
}
private void dfs(int[][] grid, int i, int j, Region region, boolean[][] seen) {
if (i < 0 || i == grid.length || j < 0 || j == grid[0].length)
return;
if (seen[i][j] || grid[i][j] == 2)
return;
if (grid[i][j] == 0) {
region.noninfected.add(i * grid[0].length + j);
++region.wallsRequired;
return;
}
// grid[i][j] == 1
seen[i][j] = true;
region.infected.add(i * grid[0].length + j);
dfs(grid, i + 1, j, region, seen);
dfs(grid, i - 1, j, region, seen);
dfs(grid, i, j + 1, region, seen);
dfs(grid, i, j - 1, region, seen);
}
}