https://programmers.co.kr/learn/courses/30/lessons/12905
문제 설명
0과 1로 이루어진 직사각형(행렬) vector<vector<int>> board
가 주어질 때
1로만 이루어진 정사각형의 넓이를 return하는 문제이다.
정사각형의 변은 x축,y축에 평행하다는 조건이 있으므로 마름모 형태의 정사각형은 배제한다.
행렬의 크기가 각각 1000이하의 자연수 이므로 총 1,000,000의 크기를 갖는 행렬이다. 따라서 O(n^2)의 시간이 걸리면 효율성을 통과 못 할 것으로 생각한다.
접근 방법
행렬을 처음부터 끝까지 한번만 읽으면 최대 정사각형이 나올 수 있다 생각했다.
따라서 O(n)시간에 풀 수 있다.
board[x][y] != 0
일때 board[x][y]
지점에서 위, 왼쪽, 왼쪽대각선 (즉,[x-1][y]
,[x][y-1]
,[x-1][y-1]
)의 저장된 수를 기반으로 [x][y]
지점에서 정사각형의 크기가 얼마가 되는지 알 수 있다.
[x][y]
가 추가되어 정사각형이 되려면 [x-1][y]
,[x][y-1]
,[x-1][y-1]
중 최소값+1 정사각형의 한변 길이가 된다.
이를 for문으로 탐색하면 board
에는 최종적으로 각 지점에서 정사각형의 한변 길이가 저장된다.
이를 코드로 옮겨보자면
풀이1
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int solution(vector<vector<int>> board)
{
int answer = 0;
bool f = false;
int ans = 0;
for(int i=1;i<board.size();i++){
for(int k=1;k<board[i].size();k++){
if(board[i][k]!=0){
// 해당 지점을 추가했을 때 정사각형 한변의 크기 구하기
board[i][k] = 1+min(board[i-1][k],min(board[i][k-1],board[i-1][k-1]));
// 최대값일 경우 저장
if(ans<board[i][k]) ans = board[i][k];
}
}
}
answer = ans*ans;
return answer;
}
결과1
풀이2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int solution(vector<vector<int>> board)
{
int answer = 0;
bool f = false;
int ans = 0;
if(board.size()==1||board[0].size()==1){
return 1;
}
for(int i=1;i<board.size();i++){
for(int k=1;k<board[i].size();k++){
if(board[i][k]!=0){
board[i][k] = 1+min(board[i-1][k],min(board[i][k-1],board[i-1][k-1]));
if(ans<board[i][k]) ans = board[i][k];
}
}
}
answer = ans*ans;
return answer;
}
결과2
후기
int ans=1
로 초기화 하면 정답이긴 하지만 가독성과 이해를 위해 if문을 추가했다. :)