-
프로그래머스 - 파괴되지 않은 건물 [C++]문제 풀이/프로그래머스 2023. 9. 10. 17:43반응형
이 문제는 누적합을 이용해서 푸는 문제이다. 일단 board의 최대 크기는 1,000 * 1,000 이고, skill의 최대 길이는 250,000 이다. 최악의 경우에는 skill의 모든 값이 0,0 ~ 999,999까지를 변경하는 경우이고, 이 때 250,000 * 1,000 * 1,000 이기 때문에 당연히 시간 초과가 난다. 여기서 많은 경우를 생각해봤지만, 마땅한 알고리즘이 떠오르지 않아 해설을 봤고, 새로운 개념을 알 수 있었다.
바로 누적합을 이용하는 것인데, [n1, n2] 까지의 범위 안에서 일정 숫자를 더해주고자 할 때, 반복문을 돌려 갱신하면 O(n) 시간이 걸린다. 하지만 [n1, n2 + 1] 까지 0이 저장되어있는 배열에서 n1의 위치에 더할 숫자 x를, n2 + 1 위치에 -x를 넣어주고 누적합 반복문을 돌리면 똑같은 결과를 낼 수 있다. 얼핏 보면 오히려 일을 두번 하는 것 같지만, 범위 안의 연산을 그때마다 하는게 아닌 범위에 대한 정보만을 저장하고 나중에 일괄 처리할 수 있다는 아이디어가 매우 중요하다. 이 아이디어를 사용하여 이 문제를 풀 수 있다.
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
해당 2차원 배열에서 [0, 0] ~ [2, 2] 까지 n을 더한다고 가정하면 범위 정보를 저장하는 방법은 다음과 같다.
n 0 0 -n 0 0 0 0 0 0 0 0 -n 0 0 n
이 상태에서 행 우선으로 먼저 누적합을 구하면 다음과 같이 된다.
n n n 0 0 0 0 0 0 0 0 0 -n -n -n 0
그 다음 열 우선으로 누적합을 구하면 다음과 같이 원하는 배열이 나오게 된다.
n n n 0 n n n 0 n n n 0 0 0 0 0
이를 그대로 문제에 적용하면 쉽게 문제를 풀 수 있다. 내 생각이지만 이 문제는 위의 테크닉을 알지 못하면 아마 그 자리에서 생각해내기에는 쉽지 않았을 것 같다.
#include <string> #include <vector> using namespace std; int acc[1003][1003]; int solution(vector<vector<int>> board, vector<vector<int>> skill) { int answer = 0; for (vector<int>& sk : skill) { int type = sk[0]; int r1 = sk[1]; int c1 = sk[2]; int r2 = sk[3]; int c2 = sk[4]; int degree = sk[5]; if (type == 1) { degree = -degree; } acc[r1][c1] += degree; acc[r1][c2 + 1] += -degree; acc[r2 + 1][c1] += -degree; acc[r2 + 1][c2 + 1] += degree; } for (int y = 0; y < 1003; y++) { for (int x = 0; x < 1002; x++) { acc[y][x + 1] += acc[y][x]; } } for (int x = 0; x < 1003; x++) { for (int y = 0; y < 1002; y++) { acc[y + 1][x] += acc[y][x]; } } for (int y = 0; y < board.size(); y++) { for (int x = 0; x < board[0].size(); x++) { if (board[y][x] + acc[y][x] >= 1) { answer++; } } } return answer; }
반응형'문제 풀이 > 프로그래머스' 카테고리의 다른 글
프로그래머스 - 수식 최대화 [C++] (0) 2023.10.16 프로그래머스 - 괄호 변환 [C++] (0) 2023.10.16 프로그래머스 - 사칙연산 [C++] (0) 2023.09.09 프로그래머스 - 순위 [C++] (0) 2023.09.08 프로그래머스 - 다단계 칫솔 판매 [C++] (0) 2023.09.08