배열에서 가장 큰 정사각형 찾기
프로그래머스에서 제공하는 문제 중 하나입니다.
배열 내부를 탐색하여 가장 큰 정사각형을 찾는 알고리즘입니다.
배열은 아래와 그림과 같이 제공되며 1이 정사각형일 때, 배열 내부의 가장 큰 정사각형의 값을 return 합니다.
위와같은 배열이 있으며, 가장 큰 정사각형은 아래와 같습니다.
가장 큰 정사각형이 9칸을 차지하고 있으므로 답은 9입니다.
구현하는 방법이야 여러가지가 있겠지만 10000*10000의 배열이면 성능에 문제가 생기게 됩니다.
그래서 성능을 고려하여 DP(Dynamic Programming)를 사용하여 구현할 수 있습니다.
자바스크립트로 구현한 방법은 아래와 같습니다.
function solution(board) { var answer = 0; var lengthY = board.length; var lengthX = board[0].length; var max = 0; // 행이나 열의 길이가 2 미만이라면 직접 돌리면서 1이 하나라도 있는지 체크 합니다. // 하나라도 있으면 통과. if (lengthY < 2 || lengthY < 2) { for(var i = 0 ; i < lengthY ; i++){ for(var j = 0; j < lengthX ; j++) { if (board[i][j] === 1) { max = 1; } } } } else { //아래 설명 참조 for(var i = 1 ; i < lengthY ; i++){ for(var j = 1; j < lengthX ; j++) { if(board[i][j] === 1 ){ board[i][j] = Math.min(board[i - 1][j], board[i][j - 1], board[i - 1][j - 1]) + 1; if (board[i][j] > max) { max = board[i][j]; } } } } } return Math.pow(max, 2); }
그럼 정사각형을 어떻게 찾는지 간단하게 설명하자면
- 배열의 [1][1]부터 반복문을 돌린다. (첫 번째 행, 첫 번째 열 무시, 이유는 2번 참고)
- 현재 값이 1일 경우,
좌측값, 상단값, 좌측상단값
중 가장 작은 값의 +1 한 값을 현재 값으로 할당. - 배열이 끝날 때 까지 반복.
- 배열의 가장 큰 값이 현재 배열의 가장 큰 정사각형의 값이 된다.
아래에 그림을 참고하여 어떻게 돌아가는지 봅시다.
위 알고리즘을 돌리면 배열은 아래와 같이 바뀝니다.
값을 할당하면 위와같은 결과가 나옵니다.
저렇게 바꾸는 부분에대한 주석을 추가했습니다.
// 첫 번째 행열을 제외시키기 위해서 i와 j에 1을 할당합니다. for(var i = 1 ; i < lengthY ; i++){ for(var j = 1; j < lengthX ; j++) { // 1이 아닐 경우 패스! 1인 값만 동적으로 변경해 줍니다. if(board[i][j] === 1 ){ // 현재 값의 좌측값, 상단값, 좌측상단값 중 최소값에 +1을 해줍니다. board[i][j] = Math.min(board[i - 1][j], board[i][j - 1], board[i - 1][j - 1]) + 1; // 다시 배열을 돌리는 수고를 하지않기 위해서 max값을 찾아 저장해 줍니다. if (board[i][j] > max) { max = board[i][j]; } } } }
가장 큰 3의 제곱을 한 값이 정사각형의 크기이기 때문에 저장한 max 값을 아래와 같이 처리해줍니다.
Math.pow(max, 2);
마치며
그림이 허접해서 죄송합니다.. :(