Java, DFS, 9 ms, Explanation with comments
This class Region hold the information for each region.\n\nprivate class Region {\n    // Using Set<Integer> instead of List<int[]> (int[] -> row and col pair),
This class **Region** hold the information for each region.\n```\nprivate class Region {\n    // Using Set<Integer> instead of List<int[]> (int[] -> row and col pair),\n    // as need to de-dupe the elements.\n    // If N rows and M cols.\n    // Total elements = NxM.\n    // Given row and col calculate X as: X = row * M + col.\n    // Given X calculate row and col as: row = X / M and col = X % M.\n\t\n    // Infected nodes represented by 1.\n    Set<Integer> infected = new HashSet<>();\n\n    // Uninfected neighbors represented by 0 are the ones this region can infect if not contained.\n    Set<Integer> uninfectedNeighbors = new HashSet<>();\n   \n    // Number of walls required to contain all the infected nodes (1s) in this region.\n    // Note that two infected 1s can infect the same 0, so in this case we need two walls to save one 0 from two 1s.\n    int wallsRequired = 0;\n}\n```\n\n**Steps**:\n1. Find all the regions.\n2. Get the region which has most number of uninfected neighbors. This region will cause maximum damage.\n3. For region in (2) contain the region. Mark all the infected nodes in this region as `2` to denote that these nodes are now contained and will not cause any more damage.\n4. For the remaining regions, expand by infecting the uninfected neighbors around these regions.\n5. Repeat steps (1) to (4) until there are no more regions with uninfected neighbors.\n\n```\npublic int containVirus(int[][] grid) {\n    if (grid == null || grid.length == 0) {\n        return 0;\n    }\n\n    int rows = grid.length;\n    int cols = grid[0].length;\n\n    int result = 0;\n\n    while (true) {\n        List<Region> regions = new ArrayList<>();\n\n        // Find all the regions using DFS (or can also use BFS).\n        boolean[][] visited = new boolean[rows][cols];\n        for (int row = 0; row < rows; row++) {\n            for (int col = 0; col < cols; col++) {\n                if (grid[row][col] == 1 && !visited[row][col]) {\n                    Region region = new Region();\n                    dfs(grid, row, col, visited, region);\n\n                    // Add region to list of regions only if it can cause infection.\n                    if (region.uninfectedNeighbors.size() > 0) {\n                        regions.add(region);\n                    }\n                }\n            }\n        }\n\n        // No more regions that can cause further infection, we are done.\n        if (regions.size() == 0) {\n            break;\n        }\n\n        // Sort the regions. Region which can infected most neighbors first.\n        regions.sort(new Comparator<Region>() {\n            @Override\n            public int compare(Region o1, Region o2) {\n                return o2.uninfectedNeighbors.size() - o1.uninfectedNeighbors.size();\n            }\n        });\n\n        // Build wall around region which can infect most neighbors.\n        Region regionThatCauseMostInfection = regions.remove(0);\n        result += regionThatCauseMostInfection.wallsRequired;\n\n        for (int neighbor : regionThatCauseMostInfection.infected) {\n            int row = neighbor / cols;\n            int col = neighbor % cols;\n\n            // Choosing 2 as to denote that this cell is now contained\n            // and will not cause any more infection.\n            grid[row][col] = 2;\n        }\n\n        // For remaining regions, expand (neighbors are now infected).\n        for (Region region : regions) {\n            for (int neighbor : region.uninfectedNeighbors) {\n                int row = neighbor / cols;\n                int col = neighbor % cols;\n                grid[row][col] = 1;\n            }\n        }\n    }\n\n    return result;\n}\n\nprivate void dfs(int[][] grid, int row, int col, boolean[][] visited, Region region) {\n    int rows = grid.length;\n    int cols = grid[0].length;\n\n    if (row < 0 || row >= rows || col < 0 || col >= cols || grid[row][col] == 2) {\n        return;\n    }\n\n    if (grid[row][col] == 1) {\n        // 1 is already infected.\n        // Add to the list, since we are using Set it will be deduped if added multiple times.\n        region.infected.add(row * cols + col);\n\n        // If already visited, return as we do not want to go into infinite recursion.\n        if (visited[row][col]) {\n            return;\n        }\n    }\n\n    visited[row][col] = true;\n\n    if (grid[row][col] == 0) {\n        // If 0 it is uninfected neighbor, we need a wall.\n        // Remeber we can reach this 0 multiple times from different infected neighbors i.e. 1s,\n        // and this will account for numbers of walls need to be built around this 0.\n        region.wallsRequired++;\n\n        // Add to uninfected list, it will be de-duped as we use Set.\n        region.uninfectedNeighbors.add(row * cols + col);\n        return;\n    }\n\n    // Visit neighbors.\n    dfs(grid, row + 1, col, visited, region);\n    dfs(grid, row - 1, col, visited, region);\n    dfs(grid, row, col + 1, visited, region);\n    dfs(grid, row, col - 1, visited, region);\n}\n```
['Depth-First Search', 'Java']