[프로그래머스] 가장 큰 정사각형 찾기
이번 문제는 풀다가 포기하고 질문하기에 도움을 받고 풀었습니다.
다들 천재입니다👍
접근방식
이 문제는 가장 큰 정사각형을 찾는 문제입니다.
2차원 배열에서
1 | 1 |
1 | 1 |
이렇게 있으면 가로 세로 길이가 2인 정사각형이 있다는 거고
1 | 1 | 1 |
1 | 1 | 1 |
1 | 1 | 1 |
이렇게 있으면 가로 세로 길이가 3인 정사각형이 있다는 겁니다.
테스트 1로 설명을 하자면
board = [[0,1,1,1],[1,1,1,1],[1,1,1,1],[0,0,1,0]]
0 | 1 | 1 | 1 |
1 | 1 | 1 | 1 |
1 | 1 | 1 | 1 |
0 | 0 | 1 | 0 |
만약 여기서 길이가 2인 정사각형이 있는지 확인을 하려면
board[row][col] = 1이야 되고
board[row-1][col]
board[row][col-1]
board[row-1][col-1]
이 다 1이야 됩니다.
밑에 3개
board[row-1][col]
board[row][col-1]
board[row-1][col-1]
가 가능하게 하려면 row, col이 0일 경우 오류가 나옵니다.
그래서 먼저 row, col이 0인 경우를 제외하고 board[row][col] = 1인 경우를 찾은 후
board[row-1][col]
board[row][col-1]
board[row-1][col-1]
을 구하면 됩니다.
이 구한 값으로 어떻게 가장 긴 정사각형의 길이를 어떻게 구하냐면
이미지를 보시면 쉽게 이해하실 수 있습니다.
이 이미지를 보시면
노랑 : board[row][col]이 1인 값
주황, 초록, 하늘 : board[row][col]기준으로 board[row-1][col], board[row][col-1], board[row-1][col-1]값
빨강 글씨 : 주황, 초록, 하늘의 3가지 수 중에서 가장 작은 값 +1
이미지를 를 보시면
board[row][col]=== 1이면
board[row][col]을 기준으로 board[row-1][col], board[row][col-1], board[row-1][col-1]값을 구하고
3개의 값 중에서 가장 작은 값에 +1을 해준 뒤 board[row][col]에 넣어주었습니다.
그러면 board[row][col]이 1일 경우
board[row-1][col], board[row][col-1], board[row-1][col-1]중 하나가 0이면 이 정사각형은 2가 될 수 없습니다.
board[row-1][col], board[row][col-1], board[row-1][col-1]중 하나가 1이면 이 정사각형은 2가 됩니다.
board[row][col]가 2로 바뀐 값에 board[row-1][col], board[row][col-1], board[row-1][col-1]에서 가장 작은 값이 2이면 3으로 교체해주면 됩니다.
즉 누적해서 값을 변화시켜주면 됩니다.
해결방안
function solution(board)
{
for(let row=1; row<board.length; row++){
for(let col=1; col<board[0].length; col++){
if(board[row][col] === 1){
board[row][col] = Math.min(board[row-1][col], board[row][col-1], board[row-1][col-1])+1;
}
}
}
return Math.max(...board.map(a=> Math.max(...a)))**2;
}
해결방안 순서
- 중복 for문으로 조건에 따라 board[row][col]를 교체해 주기
- 바뀐 board 2차원 배열에서 가장 큰 수의 제곱 구하기
1단계. 중복 for문으로 조건에 따라 board[row][col]를 교체해 주기
for(let row=1; row<board.length; row++){
for(let col=1; col<board[0].length; col++){
if(board[row][col] === 1){
board[row][col] = Math.min(board[row-1][col], board[row][col-1], board[row-1][col-1])+1;
}
}
}
접근방법에서 설명을 했지만 이번 문제는
board[row][col]가 1이면
board[row-1][col], board[row][col-1], board[row-1][col-1]값 중에서 가장 작은 값 +1을 해주는 문제입니다.
board[row-1][col], board[row][col-1], board[row-1][col-1]를 구하려면 row와 col이 0이면 안됩니다.
row와 col이 0이면 -1을 해주었을 때 -1이 되기 때문에 없는 값이 되어 오류가 나옵니다.
그래서 for문을 사용했을 때 0부터가 아닌 1부터 시작을 해주었습니다.
그럼 board[row][col]===1인 경우를 찾고
board[row][col]===1이면
board[row-1][col], board[row][col-1], board[row-1][col-1]값 중에서 가장 작은 값 +1을 해주고
그 값을 다시 board[row][col]에 담아 주면 됩니다.
2단계. 바뀐 board 2차원 배열에서 가장 큰 수의 제곱 구하기
return Math.max(...board.map(a=> Math.max(...a)))**2;
이 문제는 정사각형의 길이를 구하는 문제가 아니라 넓이를 구하는 문제입니다.
정사각형 넓이는 길이 제곱을 해주면 됩니다.
1단계에서 board배열을 새롭게 바꾸어 주었습니다.
기존 board배열에서는 0과 1만 존재했지만
새롭게 바꾸어준 board배열에서는 0,1,2,3... 등 0과 1이 아닌 수도 있을 수도 있고 없을 수도 있습니다.
새롭게 바꾸어준 board배열에서 가장 큰 수를 찾으면 됩니다.
가장 큰 수를 찾고 싶지만 board배열은 2차원 배열이라 애매해집니다.
그래서 board[0], board[1]... 에서 최댓값을 구한 뒤
board[0], board[1]...의 최댓값을 모은 뒤 다시 그 값에서 최댓값을 구해주었습니다.
제곱은 Math.pow()을 사용하는 방법도 있지만 간단하게 **을 사용해주는 방법도 있습니다.
- Math.pow(7, 3) : 7의 3제곱
- 7 ** 3 : 7의 3제곱
여기까지 프로그래머스 가장 큰 정사각형 찾기 해결방안에 대해 설명해보았습니다.