[코드트리 조별과제 5주차 코딩테스트 연습] 사각형 칠하기 (잔해물 덮기) 문제 풀이 모음 with 자바스크립트(Javascript) & 자바(Java)

Re_Go·2024년 8월 18일
0

코딩테스트연습

목록 보기
105/106
post-thumbnail

1. 첫번째 문제 풀이(2024-08-12)

이번 문제의 경우 저번에 풀었던 문제보다 제법 난이도가 많이 하향이 되었던지라 생각보다 수월하게 풀었던 문제였습니다. 이차원 배열의 좌표를 이용해서 해당 사각형의 가로, 세로 길이만큼 1을 만들어주면 되는데요.

대신 저번에는 일일이 딱 맞는 음수 배열의 범위를 구한 대에 비해, 이번에는 그냥 편하게 음수 범위만큼 오프셋을 주어봤습니다. 무슨 말이냐면,

만약 해당 수의 범위가 -100 <= n <= 100의 범위라고 한다면 각각의 가로, 세로 값에 딱 100만큼 (음수 만큼) 더해서 양수로 만든 뒤 0을 포함해 201을 좌표 배열의 범위로 설정해서 좀 수월하게 풀 수 있었습니다. (배열 범위를 만들라는게 이런 말인줄 난 그땐 몰랐지...)

아무튼 이번 문제에 대한 코드 풀이에 대해서 좀 설명을 드리자면 다음과 같이 풀었는데요.

  1. 첫번째 직사각형의 범위만큼 이중 반복문으로 1을 배열에 삽입
  2. 두번째 직사각형의 범위만큼 이중 반복문을 돌면서 해당 좌표가 1인 경우 (첫번째 직사각형이 존재하는 경우) 0으로 바꿔서 덮어버리기
  3. 남아있는 첫번째 직사각형의 경계값, 즉 1이 남아있는 구간을 찾아 각각의 가로와 세로 영역의 최소값과 최대값을 찾고
  4. 찾아낸 각각의 값들 중 각 가로, 세로값의 최대값이 마찬가지인 가로 및 세로값의 최소값보다 크거나 같은 경우, 즉 첫번째 직사각형의 범위가 살아있는 경우 각각 최대값에서 최소값을 빼어 가로와 세로 길이를 구한 뒤 1을 더해서(1을 더하는 이유는 0의 범위까지 생각해야 하기 때문)
  5. 덮어야 하는 최소한의 범위, 즉 최소한 덮어야 하는 실제 직사각형의 길이를 가로와 세로값을 곱한 뒤 출력하고
  6. 찾아낸 값 중 각각의 최대값들이 최소값보다 작은 경우, 즉 두번째 직사각형이 첫번째 직사각형을 집어 삼키고 난 뒤라 남아있는 첫번째 직사각형의 영역이 아예 없는 경우에는 0을 출력하도록 함.

특히 이번 문제는 제가 그림을 만들다가 그냥 텍스트로 대체해도 될 정도로 무난할 것 같아서(못해먹을 것) 텍스트로 좀 대체를 하게 되었습니다.

그럼 해당 문제에 대한 JS 코드를 보여드리도록 하겠습니다!

  1. JS 버전
const fs = require('fs');
const input = fs.readFileSync('/dev/stdin').toString().trim().split("\n");

// 첫 번째 직사각형 좌표
const [x1_A, y1_A, x2_A, y2_A] = input[0].split(" ").map(Number);
// 두 번째 직사각형 좌표
const [x1_B, y1_B, x2_B, y2_B] = input[1].split(" ").map(Number);

// 좌표 오프셋과 배열 크기 정의
const offset = 1000;
const coordinate = 2001; // -1000 to 1000 inclusive

// 2차원 배열을 초기화
const arr = Array.from({ length: coordinate }, () => Array(coordinate).fill(0));

// 첫 번째 직사각형의 영역을 1로 표시
for (let row = x1_A + offset; row < x2_A + offset; row++) {
    for (let col = y1_A + offset; col < y2_A + offset; col++) {
        arr[row][col] = 1;
    }
}

// 두 번째 직사각형의 영역을 덮기 작업
for (let row = x1_B + offset; row < x2_B + offset; row++) {
    for (let col = y1_B + offset; col < y2_B + offset; col++) {
        if (arr[row][col] === 1) {
            arr[row][col] = 0; // 직사각형 B에 의해 덮인 영역
        }
    }
}

// 남아있는 첫 번째 직사각형의 경계값을 찾기 위해 시작값(minX, minY는 최대값으로)과 끝 값(maxX와maxY는 최소값)으로 세팅
let minX = Number.MAX_SAFE_INTEGER;
let maxX = Number.MIN_SAFE_INTEGER;
let minY = Number.MAX_SAFE_INTEGER;
let maxY = Number.MIN_SAFE_INTEGER;

// 좌표 전체를 수색하면서 시작값과 각 해당 row, col의 현재 좌표를 비교해 더 작은 값을 시작값으로 세팅
// 마찬가지로 끝 값 또한 위의 로직대로 수행
for (let row = 0; row < coordinate; row++) {
    for (let col = 0; col < coordinate; col++) {
        if (arr[row][col] === 1) {
            minX = Math.min(minX, row);
            maxX = Math.max(maxX, row);
            minY = Math.min(minY, col);
            maxY = Math.max(maxY, col);
        }
    }
}

// 덮어야할 직사각형의 유효한 영역이 존재하는 경우 width와 height을 있는 그대로 곱해서 그 면적을 출력
if (maxX >= minX && maxY >= minY) {
    const width = maxX - minX + 1;
    const height = maxY - minY + 1;
    const area = width * height;
    console.log(area);
} else {
    // 없는 경우 출력해야하는 값 자체(덮어야 할 곳 자체)가 없기 때문에 0을 출력
    console.log(0);
}
  1. JAVA 버전
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 첫 번째 직사각형 좌표
        int x1_A = scanner.nextInt();
        int y1_A = scanner.nextInt();
        int x2_A = scanner.nextInt();
        int y2_A = scanner.nextInt();

        // 두 번째 직사각형 좌표
        int x1_B = scanner.nextInt();
        int y1_B = scanner.nextInt();
        int x2_B = scanner.nextInt();
        int y2_B = scanner.nextInt();

        // 좌표 오프셋과 배열 크기 정의
        int offset = 1000;
        int coordinate = 2001; // -1000 to 1000 inclusive

        // 2차원 배열을 초기화
        int[][] arr = new int[coordinate][coordinate];

        // 첫 번째 직사각형의 영역을 1로 표시
        for (int row = x1_A + offset; row < x2_A + offset; row++) {
            for (int col = y1_A + offset; col < y2_A + offset; col++) {
                arr[row][col] = 1;
            }
        }

        // 두 번째 직사각형의 영역을 덮기 작업
        for (int row = x1_B + offset; row < x2_B + offset; row++) {
            for (int col = y1_B + offset; col < y2_B + offset; col++) {
                if (arr[row][col] == 1) {
                    arr[row][col] = 0; // 직사각형 B에 의해 덮인 영역
                }
            }
        }

        // 남아있는 첫 번째 직사각형의 경계값을 찾기 위해 시작값(minX, minY는 최대값으로)과 끝 값(maxX와maxY는 최소값)으로 세팅
        int minX = Integer.MAX_VALUE;
        int maxX = Integer.MIN_VALUE;
        int minY = Integer.MAX_VALUE;
        int maxY = Integer.MIN_VALUE;

        // 좌표 전체를 수색하면서 시작값과 각 해당 row, col의 현재 좌표를 비교해 더 작은 값을 시작값으로 세팅
        // 마찬가지로 끝 값 또한 위의 로직대로 수행
        for (int row = 0; row < coordinate; row++) {
            for (int col = 0; col < coordinate; col++) {
                if (arr[row][col] == 1) {
                    minX = Math.min(minX, row);
                    maxX = Math.max(maxX, row);
                    minY = Math.min(minY, col);
                    maxY = Math.max(maxY, col);
                }
            }
        }

        // 덮어야할 직사각형의 유효한 영역이 존재하는 경우 width와 height을 있는 그대로 곱해서 그 면적을 출력
        if (maxX >= minX && maxY >= minY) {
            int width = maxX - minX + 1;
            int height = maxY - minY + 1;
            int area = width * height;
            System.out.println(area);
        } else {
            // 없는 경우 출력해야하는 값 자체(덮어야 할 곳 자체)가 없기 때문에 0을 출력
            System.out.println(0);
        }
    }
}

이번에는 점점 일정이 빡빡해지다보니... 시간도 없고 해서 알고리즘 공부도 시작할 겸 알고리즘 기초부터 공부를 시작해서인지 코테 공부를 잘 하지 못했는데요.

근데 알고리즘을 시작하다보니 와... 진짜 쉽게 설명을 해줘도 은근 어렵더라고요... (한편으로는 이게 공부를 하는게 맞나 싶기도 하고...)

그래서 오래 전(사실 작년임 ㅋ...) 사두었던 알고리즘 강좌 (다행히도 JS 강의가 있다!)를 봉인 해제 하기로 했습니다.

뭐 내년 까지 취준 기간을 잡고 있는 만큼 그래도 포기하지 말고 일단 계속 부딪혀보자는 마인드로 임하자는 마음이라서 코테를 풀다보면 쌓여가는 연동 커밋을 보면 또 위안 아닌 위안을 얻기도 합니다...

profile
인생은 본인의 삶을 곱씹어보는 R과 타인의 삶을 배워 나아가는 L의 연속이다.

0개의 댓글