codingtest

파괴되지 않은 건물

2025-10-13
2분 분량
JAVA프로그래머스

문제 링크

문제 풀이 시간 : 42분

문제 요약

  • N x M 크기의 보드(board) 가 있으며, 각 칸에는 건물의 내구도(정수) 가 있음
  • 적과 아군이 번갈아가며 직사각형 영역에 스킬(skill)을 사용함
  • 모든 스킬이 적용된 후, 파괴되지 않은 건물)의 개수를 구해야 함

문제 풀이

이 문제는 보고 2차원 누적합을 사용해야 하나? 라고 생각이 들었다.

하지만 좀 생각해보니 2차원 누적합은 아니고 비슷하게 풀이를 할 수 있는 문제였다.

문제의 예시에서 처럼 5*4의 배열이 있고, 0,0 ~ 3,4에 4의 공격을 한다면,

아래의 사진과 같은 영역에 -4를 해줘야 할 것이다.

post image

하지만 모든 공격, 회복에 대해 이런 작업을 해준다면 당연하게도 시간초과가 난다.

그럼 이걸 어떻게 효율적으로 할 수 있을까??

같은 공격이 있다고 할 때, 우리는 아래와 같이 표시할 수 있다.

post image

이게 무슨 그림이냐?

이 그림은 2차원 차분 기법을 표현한 것이다.

처음에 했던 것과 같이 모든 칸에 값을 더하거나 빼는 대신에 사각형 범위의 네 꼭짓점에서 표시를 해두고 나중에 누적합으로 한번에 계산하는 것이다.

쉽게 설명하자면,

  • (r1, c1) 위치에는 공격이면 -값, 회복이면 +값을 더해준다.
  • (r1, c2+1) 에는 그 반대 부호로 값을 빼준다.
  • (r2+1, c1) 에도 반대 부호로 빼준다.
  • (r2+1, c2+1) 에는 첫 위치와 같이 다시 더해준다.

이렇게 하면 누적합(가로 → 세로)를 두번 하면 직사각형 전체 영역이 자동으로 채워지게 된다.

즉, 직사각형 범위에 동일한 값을 더하거나 뺀다는 연산을 O(1)O(1)에 표시하고, 나중에 누적합으로 O(N∗M)O(N*M)에 한번에 처리하는 것이다.

최종 코드

java
class Solution {
    public int solution(int[][] board, int[][] skill) {
        int answer;
        int r = board.length;
        int c = board[0].length;
        answer = r*c;
        int[][] diff = new int[r+1][c+1];
        
        for(int[] now : skill){
            int r1 = now[1];
            int r2 = now[3];
            int c1 = now[2];
            int c2 = now[4];
            //공격이면 음수, 회복이면 양수
            int num = now[0] == 1 ? now[5]*-1 : now[5];
            
            //네 꼭짓점 업데이트
            diff[r1][c1] += num;
            diff[r1][c2+1] -= num;
            diff[r2+1][c1] -= num;
            diff[r2+1][c2+1] += num;
        }
        
        //가로 방향 누적합
        for(int i=0;i<r+1;i++){
            for(int j=1;j<c+1;j++){
                diff[i][j] += diff[i][j-1];
            }
        }
        
        //세로 방향 누적합
        for(int j=0;j<c+1;j++){
            for(int i=1;i<r+1;i++)
                diff[i][j] += diff[i-1][j];
        }
        
        //최종 건물 내구도 구하기
        for(int i=0;i<r;i++){
            for(int j=0;j<c;j++){
                board[i][j] += diff[i][j];
                //내구도가 0 이하면 파괴된 건물
                if(board[i][j]<=0)
                    answer--;
            }
        }
        
        return answer;
    }
}

함께 읽으면 좋은 글

코딩 테스트2026-08-23

택배상자

order 배열은 택배 기사님이 원하는 상자 적재 순서다 기존 컨테이너 벨트는 1번부터 순서대로만 꺼낼 수 있다 보조 벨트는 스택처럼 마지막에 넣은 것부터 꺼낼 수 있다 원하는 순서대로 최대한 실을 수 있는 상자 개수를 구하는 문제다 처음에는 기존 벨트를 실제 리스트로 만들어…

코딩 테스트2026-08-23

롤케이크 자르기

topping 배열은 롤케이크에 일렬로 올라간 토핑 번호다 한 지점을 잘라 두 조각으로 나눴을 때, 양쪽 토핑 종류 수가 같아야 공평하게 나눈 것이다 공평하게 자를 수 있는 방법의 수를 구하는 문제다 처음에는 자르는 위치마다 왼쪽과 오른쪽 배열을 나눠서 각각 서로 다른 토핑…

코딩 테스트2026-08-23

할인 행사

want, number 배열로 정현이가 원하는 제품과 수량을 표현한다 discount 배열은 XYZ 마트가 매일 할인하는 제품 목록이다 연속된 10일 동안 할인 제품 종류와 수량이 want, number와 정확히 일치해야 회원가입할 수 있다 그런 시작일이 총 몇 번 있는지…

코딩 테스트2026-08-23

숫자 변환하기

자연수 x를 y로 바꾸는 데 x+n, x2, x3 세 가지 연산을 쓸 수 있다 x를 y로 바꾸는 최소 연산 횟수를 구하는 문제다 만들 수 없으면 -1을 반환한다 처음에는 x에서 시작해서 세 가지 연산을 재귀적으로 다 시도해보고 y에 도달하는 경로 중 가장 짧은 걸 고르면…