이 문제는 초기 행렬 rc와 ShiftRow, Rotate로 이루어진 operations가 주어지면 행렬 연산을 해서 결과를 출력하는 문제다.
먼저 ShiftRow는 아래로 한줄씩 밀어내는 연산으로 rc = rc[-1] + rc[:-1]라고 표현할 수 있다.
그 다음 Rotate 연산은 바깥쪽 테두리의 값들이 시계방향으로 한칸씩 이동하는 것으로 다음과 같이 표현할 수 있다.
윗줄 = rc[1][0] + rc[0][:-1]
오른줄 = rc[1:][-1] = rc[:-1][-1]
밑줄 = rc[-1][:-1] = rc[-1][1:]
왼줄 = rc[1:-1][0] = rc[2:][0]
예시
1 2 3 -> 4 1 2
4 5 6 -> 7 5 3
7 8 9 -> 8 9 6
먼저 위에 정의한 내용을 그대로 코드로 구현했다. 여기서 약간 헤맸던 부분은 이중행렬을 copy할 시에, 내부 리스트의 요소들은 copy가 안되고 같은 메모리를 사용해서 같이 변경이 된다는 것이었다. 그래서 전에 정리해놨던 얕은 복사와 깊은 복사에 대한 글을 참고하여 deepcopy를 시도했더니 되었다.
아래 코드는 정확성 테스트는 모두 통과했지만, 효율성 테스트에서 막혔다.
import copy
def rotate(rc):
height = len(rc)
width = len(rc[0])
new_rc = copy.deepcopy(rc)
# 윗줄
new_rc[0] = rc[1][:1] + rc[0][:-1]
# 오른쪽 줄
for i in range(1, height):
new_rc[i][-1] = rc[i-1][-1]
# 아랫줄
for i in range(width-1):
new_rc[-1][i] = rc[-1][i+1]
# 왼쪽 줄
for i in range(1, height-1):
new_rc[i][0] = rc[i+1][0]
return new_rc
def solution(rc, operations):
for op in operations:
if op == 'ShiftRow':
new_rc = rc[-1:] + rc[:-1]
rc = new_rc
elif op == 'Rotate':
rc = rotate(rc)
return rc
제한사항을 다시 살펴보니 주어지는 행렬의 크기도, 연산의 길이도 매우 컸다.
from collections import deque
def solution(rc, operations):
height = len(rc)
width = len(rc[0])
left_col = deque([rc[i][0] for i in range(height)])
right_col = deque([rc[i][width - 1] for i in range(height)])
rows = deque([deque(rc[i][1:width - 1]) for i in range(height)])
for op in operations:
if op == 'ShiftRow':
left_col.appendleft(left_col.pop())
rows.appendleft(rows.pop())
right_col.appendleft(right_col.pop())
else: # 'Rotate'
rows[0].appendleft(left_col.popleft())
right_col.appendleft(rows[0].pop())
rows[height - 1].append(right_col.pop())
left_col.append(rows[height - 1].popleft())
answer = []
for i in range(height):
answer.append([left_col[i]] + list(rows[i]) + [right_col[i]])
return answer
deque의 중첩 deque는 한번도 생각해보지 못한 구조였다. 결국 카카오 해설을 참고하여 풀었는데, 앞으로는 제한사항을 먼저 확인해서 풀이 방향을 정하는 연습을 해야할 것 같다.