문제 <자물쇠와 열쇠>
잠겨있는 자물쇠는 격자 한 칸의 크기가 1 x 1인 N x N 크기의 정사각 격자 형태이고 특이한 모양의 열쇠는 M x M 크기인 정사각 격자 형태로 되어 있습니다.
자물쇠에는 홈이 파여 있고 열쇠 또한 홈과 돌기 부분이 있습니다. 열쇠는 회전과 이동이 가능하며 열쇠의 돌기 부분을 자물쇠의 홈 부분에 딱 맞게 채우면 자물쇠가 열리게 되는 구조입니다. 자물쇠 영역을 벗어난 부분에 있는 열쇠의 홈과 돌기는 자물쇠를 여는 데 영향을 주지 않지만, 자물쇠 영역 내에서는 열쇠의 돌기 부분과 자물쇠의 홈 부분이 정확히 일치해야 하며 열쇠의 돌기와 자물쇠의 돌기가 만나서는 안됩니다. 또한 자물쇠의 모든 홈을 채워 비어있는 곳이 없어야 자물쇠를 열 수 있습니다.
열쇠를 나타내는 2차원 배열 key와 자물쇠를 나타내는 2차원 배열 lock이 매개변수로 주어질 때, 열쇠로 자물쇠를 열수 있으면 true를, 열 수 없으면 false를 return 하도록 solution 함수를 완성해주세요.
제한사항
- key는 M x M(3 ≤ M ≤ 20, M은 자연수)크기 2차원 배열입니다.
- lock은 N x N(3 ≤ N ≤ 20, N은 자연수)크기 2차원 배열입니다.
- M은 항상 N 이하입니다.
- key와 lock의 원소는 0 또는 1로 이루어져 있습니다.
- 0은 홈 부분, 1은 돌기 부분을 나타냅니다.
입출력
- key = [[0, 0, 0], [1, 0, 0], [0, 1, 1]]
- lock = [[1, 1, 1], [1, 1, 0], [1, 0, 1]]
- result = True
key를 시계 방향으로 90도 회전하고, 오른쪽으로 한 칸, 아래로 한 칸 이동하면 lock의 홈 부분을 정확히 모두 채울 수 있습니다.
풀이
- 자물쇠에 열쇠를 맞출 때 자물쇠 밖에 열쇠가 벗어나도 자물쇠의 모든 홈만 채우면 된다는 조건을 먼저 생각했다.
- 그러면 자물쇠를 2차원 리스트에서 중간에 위치시키고 키를 움직여가며 자물쇠의 홈 부분에 들어맞는 때가 있는지를 보면 된다.
- 자물쇠를 중간에 위치시키는 것은 for문을 통해 쉽게 나타낼 수 있었지만,
열쇠를 움직이는 게 이 문제의 요점
이었다.
- 처음에는 열쇠를 회전시키고 상하좌우로 이동하면 되겠다고 생각했다.
- 열쇠가 자물쇠의 홈을 다 채웠는지 여부를 반환하는 possible 함수와 열쇠의 회전은 구현했지만, 이동이 관건이었다.
- 결국 시간 안에 문제를 해결하지 못했는데, 자물쇠에 열쇠를 적용해 보고 적용한 것을 돌려놓는 함수를 각각 만들어 주어야 했다.
def add(x, y, k, key, board): # 열쇠를 자물쇠에 적용시키는 함수
for i in range(k):
for j in range(k):
board[x+i][y+j] += key[i][j]
def remove(x, y, k, key, board): # 열쇠를 자물쇠에서 떼어내는 함수
for i in range(k):
for j in range(k):
board[x+i][y+j] -= key[i][j]
def possible(k, l, board): # 자물쇠가 열쇠로 열리는지 여부를 반환하는 함수
for i in range(l):
for j in range(l):
if board[k+i][k+j] != 1:
return False
return True
def solution(key, lock):
k = len(key)
l = len(lock)
board = [[0] * (2 * k + l) for i in range(2 * k + l)] # 자물쇠를 중앙에 위치시키기 위한 board 생성
for i in range(l):
for j in range(l):
board[i + k][j + k] = lock[i][j] # 자물쇠 중앙에 위치시키기
for i in range(4):
key = list(map(list, zip(*key[::-1]))) # 회전
for x in range(k+l): # 자물쇠 x 방향으로 0 ~ k+l-1 만큼 이동
for y in range(k+l): # 자물쇠 y 방향으로 0 ~ k+1-1 만큼 이동
add(x, y, k, key, board) # 자물쇠에 열쇠 적용
if possible(k, l, board): # 열리는지 확인
return True
remove(x, y, k, key, board) # 자물쇠에서 열쇠 떼어내기
return False
- 열쇠를 이동시킬 때 열쇠 자체의 좌표를 이동해야겠다고 생각해 시간 안에 문제를 해결하지 못했다.
- 열쇠를 이동시키지 않고 자물쇠를 중간에 위치시킨 새로운 판에 열쇠를 적용해 보고, 떼어내는 과정을 반복하기 위해 함수가 필요했다.
- 처음에 자물쇠를 중간에 위치시키는 아이디어를 생각했을 때, 그 이후에는 자물쇠를 중간에 위치시킨 판에서 문제를 해결해야 했다!
- 그 판 안에서 열쇠를 자유롭게 이동시켜 보면서 자물쇠 부분이 모두 1로 나오는 지점이 있는지 파악했다면 좋았을 것이다.
처음에 생각한 아이디어를 기반으로 문제를 해결해 나가야겠다.
생각한 알고리즘을 구현하기 어렵다면 잘못된 방법으로 가고 있을 가능성이 크다!
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
'CS > 알고리즘' 카테고리의 다른 글
DFS & BFS (0) | 2023.03.03 |
---|---|
[이코테] 구현 - 외벽 점검 (0) | 2023.03.01 |
[이코테] 구현 - 기둥과 보 설치 (0) | 2023.02.28 |
[이코테] 구현 - 뱀 (0) | 2023.02.28 |
[이코테] 구현 - 문자열 압축 (1) | 2023.02.27 |