-
[LeetCode] 827. Making A Large Island알고리즘 문제 풀이 2021. 8. 2. 14:19
문제 출처: https://leetcode.com/problems/making-a-large-island/
Making A Large Island - LeetCode
Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.
leetcode.com
문제
n x n 사이즈의 행렬 grid가 주어진다. 단 한 개의 0을 1로 바꿀 수 있다.
이 과정(0을 1로 바꾸는 과정)을 수행한 후에 grid 내에서 가장 큰 섬의 크기를 반환하라.
섬이란, 4방향으로 연결된 1의 그룹을 말한다.
예제
Input: grid = [[1,0],[0,1]] Output: 3 Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3.
Input: grid = [[1,1],[1,0]] Output: 4 Explanation: Change the 0 to 1 and make the island bigger, only one island with area = 4.
Input: grid = [[1,1],[1,1]] Output: 4 Explanation: Can't change any 0 to 1, only one island with area = 4.
풀이
실제 수행해야 되는 내용을 그림으로 이해하기 위해서 다음의 예를 생각해보자.
위의 예는 각 구별되는 섬에 색을 칠해놓은 것이다. (1, 1) 지점의 빨간 테두리의 셀은 예시로 1로 변경할 셀에 대해서 표시를 한 것이다. 해당 지점을 1로 변경하게 되면, 상하좌우의 4방향 지점들이 영향을 받게 될 것이다. 그래서 해당 지점으로부터 상하좌우의 4방향을 보면서 섬이 있는지 체크한다. 현재 예의 경우 파란색 섬과 주황색 섬이 인접해있는 것을 알 수 있고, 이 섬을 연결하면 된다. 연결의 경우 간단하다. 파란색 섬의 경우 크기가 4이고, 주황색 섬의 경우 크기가 6이다. 그래서 연결된 섬의 크기는 4 + 6 + 1 = 11 이 된다.
위의 예제를 토대로 문제 풀이에 필요한 정보를 다음과 같이 정리할 수 있다.
- (최초 주어지는 grid 에서) 하나의 섬을 이루는 셀들의 정보
- (최초 주어지는 grid 에서) 각 섬의 크기
이러한 정보를 얻기 위해서 DFS나 Union-Find 방법 등 여러 방법이 사용될 수 있다. 여기서는 Union-Find 알고리즘을 사용했으며, Union-Find 알고리즘은 서로소 집합 자료구조를 표현할 때 사용하는 알고리즘으로, 위 문제에서는 각 섬이 서로소 집합에 해당한다.
class UnionFind { constructor(n) { // n: grid의 행(또는 열)의 크기 this.id = Array(n*n).fill(0).map((val, idx) => idx); this.sz = Array(n*n).fill(1); } root(i) { while(this.id[i] != i) { this.id[i] = this.id[this.id[i]]; i = this.id[i] } return i; } connected(p, q) { return this.root(p) == this.root(q); } union(p, a) { const i = this.root(p); const j = this.root(q); if ( i == j ) { return; } if (this.sz[i] > this.sz[j]) { this.id[j] = i; this.sz[i] += this.sz[j]; } else { this.id[i] = j; this.sz[j] += this.sz[i]; } } }
이 Union-Find를 이용하여 주어지는 grid를 표현하는 것을 코드로 작성해보자.
var largestIsland = function(grid) { const N = grid.length; const uf = new UnionFind(N); const zeroPoint = []; const m = [[1, 0], [0, 1], [-1, 0], [0, -1]]; // grid => UnionFind로 표현 for (let r = 0; r < N; r++) { for (let c = 0; c < N; c++) { if (grid[r][c] == 0) { zeroPoint.push([r, c]); continue; } const id = r * N + c; // 현재 셀의 우측과 하단 셀 확인 for (let i = 0; i < 2; i++) { const adjRow = r + m[i][0]; const adjCol = c + m[i][1]; if (adjRow >= N || adjCol >= N || grid[adjRow][adjCol] == 0) { continue; } const adjCellId = adjRow * N + adjCol; uf.uion(id, adjCellId); } } } }
주어진 grid를 통해서 구별되는 섬을 얻기 위해서, 모든 셀을 최소 한 번씩은 방문하도록 2중 반복문을 사용하였다. 각 셀을 방문할 때마다, 방문한 셀이 1 값을 갖고 있다면 그 셀의 우측과 하단 셀을 체크하여 1이라면 현재 셀과 연결과정을 수행한다. 이와 같은 과정을 통해 구별되는 섬을 얻을 수 있다. 우측과 하단의 셀만 체크하는 것은 같은 지점들을 중복해서 체크하는 과정을 제거하기 위함이다.
이 과정을 수행하면서 추가적으로 수행하는 작업은 0인 지점에 대한 좌표를 별도로 저장하는 것이다. 이후 과정에서 0인 지점을 찾기 위해 다시 grid 행렬 전체를 탐색하는 불필요한 과정을 없앨 수 있다.
다음으로 수행해야 하는 과정에 대해 생각해보면, 0인 지점들을 방문하면서 1로 변경해보고, 이때 연결되는 섬이 존재하는지 찾아보는 것이다.
var largesetIsland = function(grid) { const N = grid.length; const uf = new UnionFind(N); const zeroPoint = []; const m = [[1, 0], [0, 1], [-1, 0], [0, -1]]; // Union-Find 과정 ... const ans = Math.max(...uf.sz); // 연결되는 섬 체크 for (let [r, c] of zeroPoint) { let connectedSize = 1; const roots = new Set(); for (let i = 0; i < 4; i++) { const adjRow = r + m[i][0]; const adjCol = r + m[i][1]; if (adjRow < 0 || adjRow >= N || adjCol < 0 || adj >= N) { continue; } if (grid[adjRow][adjCol] == 0) { continue; } roots.add(adjRow * N + adjCol); } for (let root of roots) { connectedSize += uf.sz[root]; } ans = Math.max(ans, connectedSize); } return ans }
연결되는 섬을 찾을 때는 4방향 모두 체크해봐야 한다. 또한 체크를 하면서 주의해야할 점이 있는데, 찾아진 섬이 동일한 섬일 경우를 주의해야 한다. 다시 한번 아래 그림을 살펴보자.
상단의 셀 중에서 (0, 2) 지점을 보면 좌측에는 파란 섬과 연결되어 있고, 우측과 하단에는 주황 섬과 연결되어 있다. 자칫이 지점에 대해서 잘못 계산하게 되면 주황 섬을 두 번 고려한 결과인 4 + 6 + 6 + 1 = 17 이 된다. 이러한 상황을 회피하고자 집합(set) 자료구조를 사용하여 동일한 섬이 여러 번 고려되지 않도록 코드를 구성하였다.
Github: 827.js
GitHub - opwe37/Algorithm-Study
Contribute to opwe37/Algorithm-Study development by creating an account on GitHub.
github.com
'알고리즘 문제 풀이' 카테고리의 다른 글
[LeetCode] 113. Path Sum II (0) 2021.08.05 [LeetCode] 90. Subsets Ⅱ (0) 2021.08.04 [LeetCode] 542. 01 Matrix (0) 2021.07.30 [LeetCoe] 932. Beautiful Array (0) 2021.07.29 [LeetCode] 16. 3Sum Closeset (0) 2021.07.28