ONE OF THE HARDEST QUESTIONS I EVER SOLVED || DFS || 30 MS || JAVA
Code\n\nclass AreaInfo {\n    Set<List<Integer>> nodes;\n    int id;\n    int numExposed;\n\n    public AreaInfo(int id) {\n        this.nodes = new HashSet<>()
# Code\n```\nclass AreaInfo {\n    Set<List<Integer>> nodes;\n    int id;\n    int numExposed;\n\n    public AreaInfo(int id) {\n        this.nodes = new HashSet<>();\n        this.id = id;\n        this.numExposed = 0;\n    }\n}\n\nclass Solution {\n    private final int HEALTHY = 0, UNHEALTHY = 1, FOUND = 2, CONTAMINATED = 3;\n    private final List<Integer[]> directions = List.of(\n            new Integer[] {0, 1}, new Integer[] {0, -1},\n            new Integer[] {1, 0}, new Integer[] {-1, 0}\n    );\n    private Set<List<Integer>> exposed = new HashSet<>();\n\n    public int containVirus(int[][] isInfected) {\n        Map<Integer, AreaInfo> infectedAreas = getInfectedAreas(isInfected);\n        int currentArea = infectedAreas.values().stream().sorted((o1, o2) -> o2.numExposed - o1.numExposed)\n                .map(i-> i.id).limit(1).findFirst().orElse(-1);\n        int numWalls = 0;\n        while (currentArea != -1) {\n            AreaInfo areaInfo = infectedAreas.get(currentArea);\n            List<Integer> start = areaInfo.nodes.stream().limit(1).collect(Collectors.toList()).get(0);\n            numWalls += surroundWithWalls(start.get(0), start.get(1), isInfected, 0);\n            int finalCurrentArea = currentArea;\n            infectedAreas.values().forEach(area-> {\n                if(area.id != finalCurrentArea) {\n                    Set<List<Integer>> initialNodes = new HashSet<>(area.nodes);\n                    initialNodes.forEach(node -> {\n                        expandVirus(node.get(0), node.get(1), isInfected, area, 0);\n                    });\n                }\n            });\n            infectedAreas = getInfectedAreas(isInfected);\n            currentArea = infectedAreas.values().stream().sorted((o1, o2) -> o2.numExposed - o1.numExposed)\n                    .map(i-> i.id).limit(1).findFirst().orElse(-1);\n        }\n        return numWalls;\n    }\n\n    private void expandVirus(Integer i, Integer j, int[][] isInfected, AreaInfo areaInfo, int depth) {\n        if(isInfected[i][j] == CONTAMINATED) return;\n        areaInfo.nodes.add(List.of(i, j));\n        isInfected[i][j] = 1;\n        for (Integer[] direction: directions) {\n            int x = direction[0] + i, y = direction[1] + j;\n            if(depth == 0 && isValid(x, y , isInfected) && isInfected[x][y] == HEALTHY)\n                expandVirus(x, y, isInfected, areaInfo, depth + 1);\n        }\n    }\n\n    private int surroundWithWalls(int i, int j, int[][] isInfected, int walls) {\n        if(isInfected[i][j] == CONTAMINATED) return 0;\n        isInfected[i][j] = CONTAMINATED;\n        for (Integer[] direction: directions) {\n            int x = direction[0] + i, y = direction[1] + j;\n            if(isValid(x, y , isInfected) && isInfected[x][y] == HEALTHY) {\n                walls++;\n            }\n        }\n        for (Integer[] direction: directions) {\n            int x = direction[0] + i, y = direction[1] + j;\n            if(isValid(x, y , isInfected) && isInfected[x][y] == FOUND)\n                walls = surroundWithWalls(x, y, isInfected, walls);\n        }\n        return walls;\n    }\n\n    private Map<Integer, AreaInfo> getInfectedAreas(int[][] isInfected) {\n        Map<Integer, AreaInfo> infectedAreas = new HashMap<>();\n        int areaId =  0;\n        for (int i = 0; i < isInfected.length; i++) {\n            for (int j = 0; j < isInfected[0].length; j++) {\n                if(isInfected[i][j] == 1) {\n                    AreaInfo areaInfo = new AreaInfo(areaId);\n                    exposed = new HashSet<>();\n                    searchInfected(i, j, isInfected, areaInfo);\n                    infectedAreas.put(areaInfo.id, areaInfo);\n                    areaId++;\n                }\n            }\n        }\n        return infectedAreas;\n    }\n\n    private void searchInfected(int i, int j, int[][] isInfected, AreaInfo areaInfo) {\n        if(isInfected[i][j] == CONTAMINATED) return;\n        areaInfo.nodes.add(List.of(i, j));\n        isInfected[i][j] = FOUND;\n        for (Integer[] direction: directions) {\n            int x = direction[0] + i, y = direction[1] + j;\n            if(isValid(x, y , isInfected) && !exposed.contains(List.of(x, y)) && isInfected[x][y] == HEALTHY) {\n                areaInfo.numExposed++;\n                exposed.add(List.of(x, y));\n            }\n        }\n        for (Integer[] direction: directions) {\n            int x = direction[0] + i, y = direction[1] + j;\n            if(isValid(x, y , isInfected) && isInfected[x][y] == UNHEALTHY)\n                searchInfected(x, y, isInfected, areaInfo);\n        }\n    }\n\n    private boolean isValid(int i, int j, int[][] isInfected) {\n        return i >= 0 && i < isInfected.length && j >= 0 && j < isInfected[0].length;\n    }\n}\n```
['Depth-First Search', 'Sorting', 'Matrix', 'Java']