[프로그래머스] 표 병합 - JAVA
https://school.programmers.co.kr/learn/courses/30/lessons/150366
풀이
union-find를 이용한 구현 문제였다.
MERGE명령에 대한 설명을 읽고 union-find를 사용해야겠다고 생각했다. 병합된 셀의 어느 위치를 선택하더라도 병합된 셀로 접근한다는 부분에서 union-find에서 find를 해야겠다는 생각이 들었다.
parent 배열을 1차원으로 만들기 위해 2501사이즈의 배열로 만들었다. 표의 크기가 50X50이기 때문에 (r,c)의 좌표를 (r-1)X50+c로 바꿔 넣어줬다.
union-find 메소드들을 만들고 나서는 문제에 써있는대로 명령어들에 따른 기능을 구현했다.
주의할 점은 UNMERGE명령 중 find로 루트를 찾아 그 값을 루트로 갖는 셀들을 병합 해제해 주어야 하는데, 바로 parent를 i로 바꾸면 중간에 루트로 가지 못하는 셀들이 생긴다. 따라서, 1차로 같은 루트를 가진 셀들을 임시리스트에 넣어놓고 2차로 parent배열을 초기화해주었다.
메모리: 82.6MB
시간: 9.62ms
언어: Java 11
코드
import java.util.*;
class Solution {
static int[] parent = new int[2501];
static String[] table = new String[2501];
static List<String> resultList;
private static void init() {
parent = new int[2501];
table = new String[2501];
resultList = new ArrayList<>();
for(int i = 1; i < 2501; i++) {
parent[i] = i;
table[i] = "";
}
}
private static int find(int x) {
if(x == parent[x]) {
return x;
}
return parent[x] = find(parent[x]);
}
private static void union(int x, int y) {
int px = find(x);
int py = find(y);
parent[py] = px;
}
public String[] solution(String[] commands) {
init();
for(String command : commands) {
String[] line = command.split(" ");
switch(line[0]) {
case "UPDATE":
if(line.length == 4) {
updateOneCell(getCellNumber(line[1], line[2]), line[3]);
}else {
updateCellAtoB(line[1], line[2]);
}
break;
case "MERGE":
mergeCell(getCellNumber(line[1], line[2]), getCellNumber(line[3], line[4]));
break;
case "UNMERGE":
unMergeCell(getCellNumber(line[1], line[2]));
break;
case "PRINT":
printCell(getCellNumber(line[1], line[2]));
break;
}
}
String[] answer = resultList.toArray(new String[resultList.size()]);
return answer;
}
// 셀 번호 변환. (2, 2) -> 52
private static int getCellNumber(String a, String b) {
int r = Integer.parseInt(a);
int c = Integer.parseInt(b);
return 50 * (r - 1) + c;
}
// 한 셀 바꾸기. 부모를 찾아서 바꾼다.
private static void updateOneCell(int idx, String val) {
table[find(idx)] = val;
}
// 같은 값인 모든 셀 바꾸기.
private static void updateCellAtoB(String val1, String val2) {
for(int i = 1; i < 2501; i++) {
if(table[i].equals(val1)) {
table[i] = val2;
}
}
}
// 셀 병합하기. 부모를 찾아 union한다. 값은 a에 넣고 b는 빈칸.
private static void mergeCell(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if(rootA == rootB) {
return;
}
String val = table[rootA];
if(val.length() == 0) {
val = table[rootB];
}
table[rootA] = val;
table[rootB] = "";
union(rootA, rootB);
}
// 병합 해제. 부모를 찾아서 같은 부모인 것들 리스트에 담아두고 병합 풀기.
private static void unMergeCell(int idx) {
int root = find(idx);
String val = table[root];
List<Integer> tmpList = new ArrayList<>();
for(int i = 1; i < 2501; i++) {
if(find(i) == root) {
tmpList.add(i);
}
}
for(Integer a : tmpList) {
parent[a] = a;
}
table[root] = "";
table[idx] = val;
}
// 출력 리스트에 담기.
private static void printCell(int idx) {
String val = table[find(idx)];
if(val.length() == 0) {
val = "EMPTY";
}
resultList.add(val);
}
}