기둥과 보 설치

태그: , ,

카테고리: ,


출처 프로그래머스 - 기둥과 보 설치

사용 언어 자바

제한 사항

  • n은 5 이상 100 이하인 자연수입니다.
  • build_frame의 세로(행) 길이는 1 이상 1,000 이하입니다.
  • build_frame의 가로(열) 길이는 4입니다.
  • build_frame의 원소는 [x, y, a, b]형태입니다.
    • x, y는 기둥, 보를 설치 또는 삭제할 교차점의 좌표이며, [가로 좌표, 세로 좌표] 형태입니다.
    • a는 설치 또는 삭제할 구조물의 종류를 나타내며, 0은 기둥, 1은 보를 나타냅니다.
    • b는 구조물을 설치할 지, 혹은 삭제할 지를 나타내며 0은 삭제, 1은 설치를 나타냅니다.
    • 벽면을 벗어나게 기둥, 보를 설치하는 경우는 없습니다.
    • 바닥에 보를 설치 하는 경우는 없습니다.
  • 구조물은 교차점 좌표를 기준으로 보는 오른쪽, 기둥은 위쪽 방향으로 설치 또는 삭제합니다.
  • 구조물이 겹치도록 설치하는 경우와, 없는 구조물을 삭제하는 경우는 입력으로 주어지지 않습니다.
  • 최종 구조물의 상태는 아래 규칙에 맞춰 return 해주세요.
    • return 하는 배열은 가로(열) 길이가 3인 2차원 배열로, 각 구조물의 좌표를 담고있어야 합니다.
    • return 하는 배열의 원소는 [x, y, a] 형식입니다.
    • x, y는 기둥, 보의 교차점 좌표이며, [가로 좌표, 세로 좌표] 형태입니다.
    • 기둥, 보는 교차점 좌표를 기준으로 오른쪽, 또는 위쪽 방향으로 설치되어 있음을 나타냅니다.
    • a는 구조물의 종류를 나타내며, 0은 기둥, 1은 보를 나타냅니다.
    • return 하는 배열은 x좌표 기준으로 오름차순 정렬하며, x좌표가 같을 경우 y좌표 기준으로 오름차순 정렬해주세요.
    • x, y좌표가 모두 같은 경우 기둥이 보보다 앞에 오면 됩니다.
  • 기둥은 바닥 위에 있거나 보의 한쪽 끝 부분 위에 있거나, 또는 다른 기둥 위에 있어야 합니다.
  • 보는 한쪽 끝 부분이 기둥 위에 있거나, 또는 양쪽 끝 부분이 다른 보와 동시에 연결되어 있어야 합니다.

입력

  • 격자 가로 세로 길이 n
  • [x, y, a, b]형태의 작업 배열 build_frame

끔찍한 경험이었다

제출 답안

import java.util.*;

class Solution {
    public int[][] solution(int n, int[][] build_frame) {
        int[][] frame = new int[n + 1][n + 1];          // 설치 현황 지도
        ArrayList<int[]> result = new ArrayList<>();

        for (int[] temp : build_frame) {
            int type = temp[2] == 0 ? 1 : 10;           // 0(기둥) = 1, 1(보) = 10

            if (temp[3] == 1) {                         // -설치-
                // if (result.contains(temp)) continue;    // 이미 설치됨 -> 생략

                result.add(temp);                       // 임시 설치
                frame[temp[0]][temp[1]] += type;

                if (hasProblem(frame, result)) {        // 불합격 -> 철거
                    result.remove(temp);
                    frame[temp[0]][temp[1]] -= type;
                }
            }
            if (temp[3] == 0) {                         // -삭제-
                int[] target = result.stream()          // 삭제 대상 확인
                        .filter(a -> a[0] == temp[0] && a[1] == temp[1] && a[2] == temp[2])
                        .findFirst().orElse(null);

                // if (target == null) continue;           // 그런거 없음 -> 생략

                result.remove(target);                  // 임시 철거
                frame[temp[0]][temp[1]] -= type;

                if (hasProblem(frame, result)) {        // 불합격 -> 재설치
                    result.add(target);
                    frame[temp[0]][temp[1]] += type;
                }
            }
        }

        result.sort((a, b) -> a[0] - b[0] != 0 ? a[0] - b[0]
                            : a[1] - b[1] != 0 ? a[1] - b[1]
                            : a[2] - b[2]);

        int[][] answer = new int[result.size()][3];
        for (int i = 0; i < result.size(); i++) {
            int[] temp = result.get(i);
            answer[i] = new int[]{temp[0], temp[1], temp[2]};
        }
        return answer;
    }

    // 구조물 전체 확인
    public boolean hasProblem(int[][] frame, ArrayList<int[]> result) {
        for (int[] i : result) {
            if ((i[2] == 0 && !validP(frame, i)) ||
                (i[2] == 1 && !validB(frame, i))) return true;
        }
        return false;
    }

    // 기둥 적합성 확인
    public boolean validP(int[][] frame, int[] i) {
        int x = i[0];
        int y = i[1];
        // 바닥 위 || 다른 기둥 위 || 좌측 보 위 || 우측 보 위
        return (y <= 0) || (frame[x][y - 1] % 10 >= 1)
            || (x > 0 && frame[x - 1][y] >= 10) || (frame[x][y] >= 10);
    }

    // 보 적합성 확인
    public boolean validB(int[][] frame, int[] i) {
        int x = i[0];
        int y = i[1];
        int mLen = frame.length - 2;
        // 좌하단 기둥 || 우하단 기둥 || (좌표 범위 확인 && 양쪽 보)
        return (frame[x][y - 1] % 10 == 1) || (frame[x + 1][y - 1] % 10 == 1)
            || ((0 < x && x < mLen) && (frame[x - 1][y] >= 10) && (frame[x + 1][y] >= 10));
    }
}

댓글남기기