문제 설명 : https://school.programmers.co.kr/learn/courses/30/lessons/60059
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 요약 :
- 자물쇠의 빈 공간에 열쇠의 돌기가 맞아야 한다.
- 자물쇠의 돌기와 열쇠의 돌기가 맞닿으면 안 된다.
- 키는 특정 부분만 사용하여 자물쇠를 열 수 있다.
문제 풀이 시간 : 1시간 30분
문제 성공 여부 : 성공
접근 방법(성공) :
- 자물쇠에 대해 가능한 모든 열쇠 모양을 시뮬레이션

다음과 같은 키와 자물쇠가 주어진다고 보자.
자물쇠에 대해 모든 key 모양을 다 대입시키려면, 적어도 키의 한 칸은 자물쇠와 맞물려야 한다.
따라서, 자물쇠의 가장 왼쪽 상단(0,0)을 key의 가장 오른쪽 아래인 (2,2)를 맞물려본다.



이 풀이방법을 위한 준비물은 다음과 같다.
1. key를 시계방향으로 회전시킨 4개의 배열(0,90,180,270)
2. 위와 같은 그림과 같이, 모든 키를 대입할 수 있는 중앙배치된 자물쇠 배열(arr)
1번은 말 그대로 key 배열을 90도씩 돌려가며, 저장해 두면 된다.
2번은 (keyRow-1 + lockRow + keyRow-1) * (keyCol-1 + lockCol + keyCol-1)의 배열을 만들고 중앙에 lock을 복사하면 된다.
그렇다면 시간복잡도는 어떻게 될까?
위의 표를 기준으로 보면 (0,0) ~ (4,4)까지 각각의 인덱스에 대해 4번의 검사(키를 회전한 4번 비교)를 진행한다.
식으로 표현하면 4 * (N+M-1)^2만큼의 탐색이 고정적으로 진행된다고 보면 된다.
또한, 검사를 진행할 때 M*M개를 arr에 대입해 보고 자물쇠 크기인 N*N을 검사하고 M*M개를 다시 원상복구 시킨다고 보면
4*(N+M-1)^2 * (M*M+N*N+M*M) 정도의 시간이 걸린다고 보면 된다.(물론 더 효율적으로 검사할 수 있는 방법이 있다.)
N과 M이 최대 20까지 올 수 있기에 총 연산 횟수는 약 7백만 개임으로 시간초과의 걱정은 없다.
이제 구현만이 남았는데, 살짝 골치 아팠던 회전 로직을 설명해 보겠다.
회전 로직
const getRotateImages = (arr) => {
const rotateImages = [arr];
for(let i=0; i<3; i++){
const rotateImage = getRotateImage(rotateImages[i]); // 이전 배열을 넣어 90도씩 회전시킨다.
rotateImages.push(rotateImage);
}
return rotateImages;
}
해당 함수는 배열을 입력받아 0도, 90도, 180도, 270도 회전시킨 4가지 배열을 반환해 주는 함수이다.
이전 결괏값(배열)을 인자로 getRotateImage 함수에 넣어 계속 90도씩 돌려준다.
const getRotateImage = (arr) => {
const len = arr.length;
const rotateImage = Array.from({length:len}, ()=>Array(len).fill(0));
for(let i =0; i<len; i++){
for(let j=0; j<len; j++){
rotateImage[j][len-1-i] = arr[i][j]; // 90도 회전시킨다.
}
}
return rotateImage;
}
회전 핵심 로직이다.
규칙을 생각한다고 시간을 꽤나 잡아먹었는데 코드는 아주 간단하다.
1. 현재 인덱스의 값은 회전하게 되면 col 값이 row 값이 된다.
2. row 값은 (len-1)- row를 한 값이 col이 된다.
해당 규칙을 코드로 구현하여 해결하였다.
검사 로직
검사 로직은 솔직히 좀 비효율적으로 구현하였다.
이전에 빼앗긴 시간을 급하게 해결하기 위해 쉽지만 다소 비효율적인 방법으로 접근하였다.
key 배열이 주어질 때, 가장 쉽게 비교할 수 있는 방법은 다음과 같다.
1. arr 배열 각각의 인덱스에 key 배열 각각의 인덱스 값을 더해준다.
2. lock 부분을 탐색하며 1이 아닌 값이 있을 경우 false, 없을 경우 true임을 알 수 있다.
3. 원본 arr 배열의 값이 변했기 때문에 다시 key 배열 각각의 인덱스 값을 빼준다.
const check = (arr,x,y,rotateImage) => {
const keyLen = rotateImage.length-1;
for(let i=x; i<=x+keyLen; i++){
for(let j=y; j<=y+keyLen; j++){
arr[i][j] += rotateImage[i-x][j-y]; // arr에 key값을 더해준다.
}
}
const len = arr.length;
let isTrue = true;
for(let i=keyLen; i<len-keyLen; i++ ){
for(let j=keyLen; j<len-keyLen; j++){
if(arr[i][j]!==1) { // 2거나 0이면 열 수 없으므로 false
isTrue = false;
break;
}
}
}
for(let i=x; i<=x+keyLen; i++){
for(let j=y; j<=y+keyLen; j++){
arr[i][j] -= rotateImage[i-x][j-y]; // key값을 다시 빼서 원상복구 시킨다.
}
}
return isTrue;
}
전체 코드(성공) :
function solution(key, lock) {
const keyLen = key.length-1;
const lockLen = lock.length;
const len = keyLen * 2 + lockLen;
const arr = Array.from({length:len}, ()=>Array(len).fill(0)); // 자물쇠 중앙배치 배열
for(let i=keyLen; i<keyLen+lockLen; i++){
for(let j=keyLen; j<keyLen+lockLen; j++){
arr[i][j] = lock[i-keyLen][j-keyLen]; // 자물쇠 중앙 배치
}
}
const rotateImages = getRotateImages(key); // key를 회전시킨 4가지 배열 반환
for(let i=0; i<len-keyLen; i++){
for(let j=0; j<len-keyLen; j++){
for(const rotateImage of rotateImages){
if(check(arr,i,j,rotateImage)) return true; // 해당 위치에 4번의 회전 결과를 대입
}
}
}
return false;
}
const check = (arr,x,y,rotateImage) => {
const keyLen = rotateImage.length-1;
for(let i=x; i<=x+keyLen; i++){
for(let j=y; j<=y+keyLen; j++){
arr[i][j] += rotateImage[i-x][j-y]; // arr에 key값을 더해준다.
}
}
const len = arr.length;
let isTrue = true;
for(let i=keyLen; i<len-keyLen; i++ ){
for(let j=keyLen; j<len-keyLen; j++){
if(arr[i][j]!==1) { // 2거나 0이면 열 수 없으므로 false
isTrue = false;
break;
}
}
}
for(let i=x; i<=x+keyLen; i++){
for(let j=y; j<=y+keyLen; j++){
arr[i][j] -= rotateImage[i-x][j-y]; // key값을 다시 빼서 원상복구 시킨다.
}
}
return isTrue;
}
const getRotateImages = (arr) => {
const rotateImages = [arr];
for(let i=0; i<3; i++){
const rotateImage = getRotateImage(rotateImages[i]); // 이전 배열을 넣어 90도씩 회전시킨다.
rotateImages.push(rotateImage);
}
return rotateImages;
}
const getRotateImage = (arr) => {
const len = arr.length;
const rotateImage = Array.from({length:len}, ()=>Array(len).fill(0));
for(let i =0; i<len; i++){
for(let j=0; j<len; j++){
rotateImage[j][len-1-i] = arr[i][j]; // 90도 회전시킨다.
}
}
return rotateImage;
}'코테 > 프로그래머스' 카테고리의 다른 글
| [프로그래머스] 이중우선순위큐 - Javascript (5) | 2025.08.18 |
|---|---|
| [프로그래머스] 오픈채팅방 - Javascript (4) | 2025.08.17 |
| [프로그래머스] 디펜스 게임 - Javascript (4) | 2025.08.15 |
| [프로그래머스] 방금그곡 - Javascript (8) | 2025.08.07 |
| [프로그래머스] N-Queen - Javascript (3) | 2025.08.05 |