솔직히 이 문제는 제가 여태 풀었던 코딩 문제 중에 역대급으로 어려운 문제이자 제가 이 문제를 풀면서 "아... 코테 때려칠까?" 라는 생각을 가지게 만들게 해준 문제였습니다. 그 만큼 xp도 역대급으로 높았던 문제였고, 그래서 풀어냈을때의 그 짜릿한 쾌감은... 진짜 어려웠던 만큼 역대급으로 높았지 않나 싶습니다.
아무튼 개념 설명은 이 곳을 한 번 참고해 보시면 좋을 것 같고, 그림 설명으로 코드의 흐름을 한 번 보여드리도록 하겠습니다.
거의 마지막에 W 타일이 하나가 추가됬는데 제가 깜빡하고 계산을 잘못해서.... 아무튼 애교로 봐주십쇼 ㅎㅎ
아무튼 이런 알고리즘으로 해당 코드는 동작하는데, 이때 주의할 점은 꼭 최소값 최대값을 구할 때 -1를 해주어야 한다는 것입니다. 그 이유는 타일을 셀 때 서 있는 타일부터 세기 때문이고요. (전 이것 때문에 몇 시간을 해매다 어느 귀하신 분 덕분에 해결할 수 있었습니다 ㅜㅜ)
for문을 돌리면서 범위에 대해서도 해당 포지션이 넘어갈 때 break로 for문을 끝내야 합니다.
물론 다른 분들은 넉넉히 배열을 한 십 만개에서 이십 만개를 만드셨다는데 저는 그렇게 배열을 만드는 법은 알고 있긴 한데 왠지 오기가 생겨서... 그래서 그냥 딱 정해진 만큼 배열을 만들고 범위가 넘어가는 포지션은 과감히 break로 빼버리는 선택을 했습니다.
그럼 그렇게 여섯 시간을 쌩고생 해서 겨우 풀은 문제의 JS 코드를 소개해 드리겠습니다!!
- JS 버전
const fs = require('fs'); const input = fs.readFileSync('/dev/stdin').toString().trim().split("\n"); const [lines, orderArr] = [input.shift(), input.map(arr => arr.split(" "))]; // 배열의 최소, 최대값을 구할 변수들을 선언 let min = 0; let max = 0; let num = 0; // 배열의 최소 범위와 최대 범위를 계산하는 구간, orderArr.forEach(order => { let temp = 0; if (order[1] === 'R') temp = parseInt(order[0]) - 1; else temp = -(parseInt(order[0] - 1)); num += temp; if (num < min) min = num; if (num > max) max = num; }); // size는 최대값에 최소값을 빼고 1로 보정함. 만약 최소값이 음수면 그만큼 사이즈는 넓어지고, 양수라면 그만큼 정상적으로 빼지는 만큼 배열 보정이 가능함. const size = max - min + 1; // 배열들 준비 const accumulator = Array(size).fill(0); const blackArr = Array(size).fill(0); const whiteArr = Array(size).fill(0); const colorArr = Array(size).fill(''); // 초기 position을 최소값의 절대값으로 바꿔 안전성을 보장 let position = Math.abs(min); // for문을 돌림 for (let order of orderArr) { // steps는 각 오더의 첫번째(걸음 수) 수 const steps = parseInt(order[0]); // 오더가 R(오른쪽) 이면 그림 설명대로 진행 if (order[1] === 'R') { for (let i = 0; i < steps; i++) { accumulator[position]++; blackArr[position]++; colorArr[position] = 'B'; // 중간에 검은 타일과 흰 타일의 해당 포지션의 값이 각각 2 이상이면 컬러 타일의 해당 포지션을 G로 바꿔줌 if (whiteArr[position] >= 2 && blackArr[position] >= 2) colorArr[position] = 'G'; position++; // position은 절대값이므로 음수일 리가 없는데, 만약 이 값이 음수이거나 배열의 길이를 벗어나 커진 경우, 즉 범위를 벗어난 경우라면 for문을 즉시 종료 if (position < 0 || position > accumulator.length) break; } position--; // R 명령 후 position 조정 } if (order[1] === 'L') { for (let i = 0; i < steps; i++) { accumulator[position]++; whiteArr[position]++; colorArr[position] = 'W'; if (whiteArr[position] >= 2 && blackArr[position] >= 2) colorArr[position] = 'G'; position--; if (position < 0 || position > accumulator.length) break; } position++; // L 명령 후 position 조정 } } // 결과 계산을 위한 result 배열 let result = [0, 0, 0]; // 이하 그림 설명과 같음 for (let i = 0; i < colorArr.length; i++) { if (colorArr[i] === 'W') result[0]++; if (colorArr[i] === 'B') result[1]++; if (colorArr[i] === 'G') result[2]++; } // join으로 배열의 요소를 공백으로 묶어서 양쪽 공백 제거 후 결과 출력 console.log(result.join(' ').trim());
- 자바 버전
import java.util.*; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // 입력 읽기 int lines = Integer.parseInt(scanner.nextLine().trim()); List<String[]> orderArr = new ArrayList<>(); for (int i = 0; i < lines; i++) { orderArr.add(scanner.nextLine().trim().split(" ")); } int min = 0; int max = 0; int num = 0; // Min과 Max를 정확히 계산하여 배열의 크기를 맞춤 for (String[] order : orderArr) { int steps = Integer.parseInt(order[0]); int temp = 0; if ("R".equals(order[1])) { temp = steps - 1; } else if ("L".equals(order[1])) { temp = -(steps - 1); } num += temp; if (num < min) min = num; if (num > max) max = num; } // 범위 설정: 음수 값을 보정하는 offset 사용 int size = max - min + 1; int[] accumulator = new int[size]; int[] blackArr = new int[size]; int[] whiteArr = new int[size]; char[] colorArr = new char[size]; Arrays.fill(colorArr, ' '); // 초기 position을 offset으로 설정하여 항상 양수 인덱스를 사용 int position = Math.abs(min); for (String[] order : orderArr) { int steps = Integer.parseInt(order[0]); if ("R".equals(order[1])) { for (int i = 0; i < steps; i++) { accumulator[position]++; blackArr[position]++; colorArr[position] = 'B'; if (whiteArr[position] >= 2 && blackArr[position] >= 2) { colorArr[position] = 'G'; } position++; if (position < 0 || position >= accumulator.length) break; } position--; // R 명령 후 position 조정 } if ("L".equals(order[1])) { for (int i = 0; i < steps; i++) { accumulator[position]++; whiteArr[position]++; colorArr[position] = 'W'; if (whiteArr[position] >= 2 && blackArr[position] >= 2) { colorArr[position] = 'G'; } position--; if (position < 0 || position >= accumulator.length) break; } position++; // L 명령 후 position 조정 } } // 결과 계산 int[] result = new int[3]; // W, B, G 카운트 for (int i = 0; i < colorArr.length; i++) { if (colorArr[i] == 'W') result[0]++; if (colorArr[i] == 'B') result[1]++; if (colorArr[i] == 'G') result[2]++; } // 결과 출력 System.out.println(result[0] + " " + result[1] + " " + result[2]); } }
뭐... 이번 주간 문제들은 알고리즘 푸는 방식이다보니 다르고 자시고간에 문제 그 자체를 푸느라 차이점을 못느꼈습니다. 하하... 풀어야죠뭐.... 하하....
이번에 기초 과정을 완료해서 얻은 배지까지 하나 하나 모일때마다 뿌듯하다는 생각이 들었습니다. (물론 남은 무료 기간이 얼마 남지 않았다는 걸 알게 되니까 슬퍼진다는... 그리고 이번 주는 국비 학원에서 꽤나 바빠서 코테에 신경을 쓰지 못했죠... (문제가 점점 어려워 져서 생각이 많아지는 것도 한 몫 한 듯...) 그래도 포기 하지 말고 화이팅!