[프로그래머스] 빛의 경로 사이클 (java)
zl존석동
·2022. 10. 1. 19:06
프로그래머스 lv2 빛의 경로 사이클 자바 풀이
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
문제 요약
2차원 배열 느낌으로 칸이 주어지고 각 칸마다 격자가 있다.
격자에는 빛이 동서남북에서 들어올 수 있다.
격자는 빛을 직진, 좌회전, 우회전 시킬 수 있다.
배열에 있는 모든 격자들에 대한 사이클 수를 구해라
나의 풀이
존재하는 모든 격자들에 대해 시작점으로 설정하고 해당 격자로부터 발생한 사이클을 구할 것이다.
하나의 격자에 대해 사이클을 구할 때 빛의 출처 4가지를 모두 활용해 탐색하여 사이클을 구한다.(동,서,남,북)
예를 들어 좌표 (1,1) 의 격자에 왔다고 쳤을 때 어디서 왔는지는 총 4방향인 것이고 이 4방향으로부터 시작했음을 모두 탐색해야 모든 사이클을 구할 수 있다.
주의점
1. (1,1) 에서 (2,1) 로 갔다면 (2,1) 입장에서는 서쪽으로부터 빛이 온 것이고 서쪽 출처의 (2,1) 에서 경로를 모두 탐색하나
(1,1) 에서 시작해 (2,1)을 지나도록 경로를 모두 탐색하나 같은 사이클이다.
이 부분을 필터링해주지 않으면 시간초과났다.
2. 격자 하나가 빛을 꺾는 각도는 격자가 받은 빛의 방향에 의존한다. 잘 하면 깔끔하게 이 부분을 구현할 수 있을텐데 하다보니 분기가 많아져 코드가 더러워졌다.
풀이 코드
import java.util.*;
public class 빛의경로사이클 {
static Mirror[][] mirrors;
public static int[] solution(String[] grid) {
mirrors = new Mirror[grid.length][grid[0].length()];
for (int i = 0; i < mirrors.length; i++) {
for (int j = 0; j < mirrors[0].length; j++) {
mirrors[i][j] = new Mirror(String.valueOf(grid[i].charAt(j)));
}
}
for (int i = 0; i < mirrors.length; i++) {
for (int j = 0; j < mirrors[0].length; j++) {
loop(i, j, new History(), From.LEFT);
loop(i, j, new History(), From.RIGHT);
loop(i, j, new History(), From.BOTTOM);
loop(i, j, new History(), From.TOP);
}
}
return answerList.stream().mapToInt(value -> value).sorted().toArray();
}
private static final List<Integer> answerList = new ArrayList<>();
private static void loop(int currentX, int currentY, History history, From from) {
while (true) {
if (history.size != 0
&& history.xList.get(0) == currentX && history.yList.get(0) == currentY
&& history.froms.get(0).equals(from)) {
answerList.add(history.size);
return;
}
if (mirrors[currentX][currentY].fromContains(from)) {
return;
}
mirrors[currentX][currentY].addFrom(from);
history.set(from, currentX, currentY);
Direction direction = mirrors[currentX][currentY].direction;
From to = direction.move(from);
currentX = setPoint(currentX, to.x, mirrors.length);
currentY = setPoint(currentY, to.y, mirrors[0].length);
from = to;
}
}
private static int setPoint(int current, int newValue, int range) {
if (current + newValue < 0) {
return range - 1;
}
if (current + newValue >= range) {
return 0;
}
return current + newValue;
}
static class Mirror {
Direction direction;
Set<From> set = new HashSet<>();
public void addFrom(From from) {
set.add(from);
}
public boolean fromContains(From from) {
return set.contains(from);
}
public Mirror(String direction) {
this.direction = Direction.valueOf(direction);
}
}
enum Direction {
L, S, R;
public From move(From from) {
if (this.equals(L)) {
return from.moveLeft();
}
if (this.equals(R)) {
return from.moveRight();
}
return from.moveSt();
}
}
enum From {
TOP(-1, 0), BOTTOM(1, 0), LEFT(0, -1), RIGHT(0, 1);
private final int x;
private final int y;
From(int x, int y) {
this.x = x;
this.y = y;
}
public From moveLeft() {
if (this.equals(TOP)) {
return LEFT;
}
if (this.equals(BOTTOM)) {
return RIGHT;
}
if (this.equals(LEFT)) {
return BOTTOM;
}
return TOP;
}
public From moveRight() {
if (this.equals(TOP)) {
return RIGHT;
}
if (this.equals(BOTTOM)) {
return LEFT;
}
if (this.equals(LEFT)) {
return TOP;
}
return BOTTOM;
}
public From moveSt() {
return this;
}
}
static class History {
List<From> froms = new ArrayList<>();
int size = 0;
List<Integer> xList = new ArrayList<>();
List<Integer> yList = new ArrayList<>();
public void set(From from, int x, int y) {
this.froms.add(from);
this.xList.add(x);
this.yList.add(y);
this.size++;
}
}
}
'알고리즘 & 자료구조 > 프로그래머스' 카테고리의 다른 글
| [프로그래머스] 스킬트리 (java) (0) | 2022.08.24 |
|---|---|
| [프로그래머스] 파일명 정렬 (java) (0) | 2022.08.15 |
| [프로그래머스] 파괴되지 않은 건물(java) (0) | 2022.07.18 |
| [프로그래머스] 소수찾기 (Java) (0) | 2022.02.03 |
| [프로그래머스] 다리를 지나는 트럭 (java) (0) | 2022.01.13 |