문제 설명
1와 0로 채워진 표(board)가 있습니다. 표 1칸은 1 x 1 의 정사각형으로 이루어져 있습니다. 표에서 1로 이루어진 가장 큰 정사각형을 찾아 넓이를 return 하는 solution 함수를 완성해 주세요. (단, 정사각형이란 축에 평행한 정사각형을 말합니다.)
예를 들어
1 | 2 | 3 | 4 |
0 | 1 | 1 | 1 |
1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 |
0 | 0 | 1 | 0 |
가 있다면 가장 큰 정사각형은 색칠한 칸이 되며 넓이는 9가 되므로 9를 반환해 주면 됩니다.
제한 사항
- 표(board)는 2차원 배열로 주어집니다.
- 표(board)의 행(row)의 크기 : 1,000 이하의 자연수
- 표(board)의 열(column)의 크기 : 1,000 이하의 자연수
- 표(board)의 값은 1또는 0으로만 이루어져 있습니다.
풀이
누적합을 이용하여 문제를 풀려하였다.
하지만 효율성 테스트에서 시간초과가 발생한다.
다른 접근법을 이용해야 하는데 생각이 나지 않아 여러 글을 찾아봤다.
정답은 DP였다.
dp에 기록할 내용은 해당 위치에서 만들 수 있는 가장 큰 정사각형의 한 변의 길이이다.
즉, 연속한 1의 숫자가 된다.
연속해야 하기 때문에 바로 이전의 위치만 보면 된다.
여기서 이전의 위치란 왼쪽, 위쪽, 대각이다.
예를 들어
? | ? | ? | ? |
? | V | V | ? |
? | V | O | ? |
? | ? | ? | ? |
O의 위치에서 보면 O를 추가하여 정사각형을 만든다고 했을 때, V위치 중 가장 작은 수에서 1을 더한 값이 된다.
각 칸이 자신을 오른쪽 아래 모서리로 그릴 수 있는 정사각형의 길이를 나타내기 때문이다.
전체 코드
#include <iostream>
#include<vector>
using namespace std;
int solution(vector<vector<int>> board)
{
int answer = 1;
int maxVal = 0;
vector<vector<int>> count(board.size(), vector<int>(board[0].size(), 0));
for(int i = 0; i < board.size(); i++)
{
for(int j = 0 ; j < board[0].size(); j++)
{
if(i==0 || j==0 || board[i][j] == 0)
{
if(board[i][j])
{
count[i][j] = 1;
maxVal = max(maxVal, 1);
}
continue;
}
int temp = min(count[i-1][j], count[i][j-1]);
temp = min(temp, count[i-1][j-1]) + 1;
count[i][j] = temp;
maxVal = max(maxVal, temp);
}
}
answer = maxVal*maxVal;
return answer;
}