daniel7481의 개발일지

[프로그래머스] 행렬 테두리 회전하기(2021 Dev-Matching 웹 백엔드 개발자(상반기) 본문

프로그래머스

[프로그래머스] 행렬 테두리 회전하기(2021 Dev-Matching 웹 백엔드 개발자(상반기)

daniel7481 2021. 12. 11. 18:22
반응형

https://programmers.co.kr/learn/courses/30/lessons/77485

 

코딩테스트 연습 - 행렬 테두리 회전하기

6 6 [[2,2,5,4],[3,3,6,6],[5,1,6,3]] [8, 10, 25] 3 3 [[1,1,2,2],[1,2,2,3],[2,1,3,2],[2,2,3,3]] [1, 1, 5, 3]

programmers.co.kr

문제 설명

rows x columns 크기인 행렬이 있습니다. 행렬에는 1부터 rows x columns까지의 숫자가 한 줄씩 순서대로 적혀있습니다. 이 행렬에서 직사각형 모양의 범위를 여러 번 선택해, 테두리 부분에 있는 숫자들을 시계방향으로 회전시키려 합니다. 각 회전은 (x1, y1, x2, y2)인 정수 4개로 표현하며, 그 의미는 다음과 같습니다.

  • x1 행 y1 열부터 x2 행 y2 열까지의 영역에 해당하는 직사각형에서 테두리에 있는 숫자들을 한 칸씩 시계방향으로 회전합니다.

다음은 6 x 6 크기 행렬의 예시입니다.

이 행렬에 (2, 2, 5, 4) 회전을 적용하면, 아래 그림과 같이 2행 2열부터 5행 4열까지 영역의 테두리가 시계방향으로 회전합니다. 이때, 중앙의 15와 21이 있는 영역은 회전하지 않는 것을 주의하세요.

행렬의 세로 길이(행 개수) rows, 가로 길이(열 개수) columns, 그리고 회전들의 목록 queries가 주어질 때, 각 회전들을 배열에 적용한 뒤, 그 회전에 의해 위치가 바뀐 숫자들 중 가장 작은 숫자들을 순서대로 배열에 담아 return 하도록 solution 함수를 완성해주세요.


제한사항
  • rows는 2 이상 100 이하인 자연수입니다.
  • columns는 2 이상 100 이하인 자연수입니다.
  • 처음에 행렬에는 가로 방향으로 숫자가 1부터 하나씩 증가하면서 적혀있습니다.
    • 즉, 아무 회전도 하지 않았을 때, i 행 j 열에 있는 숫자는 ((i-1) x columns + j)입니다.
  • queries의 행의 개수(회전의 개수)는 1 이상 10,000 이하입니다.
  • queries의 각 행은 4개의 정수 [x1, y1, x2, y2]입니다.
    • x1 행 y1 열부터 x2 행 y2 열까지 영역의 테두리를 시계방향으로 회전한다는 뜻입니다.
    • 1 ≤ x1 < x2 ≤ rows, 1 ≤ y1 < y2 ≤ columns입니다.
    • 모든 회전은 순서대로 이루어집니다.
    • 예를 들어, 두 번째 회전에 대한 답은 첫 번째 회전을 실행한 다음, 그 상태에서 두 번째 회전을 실행했을 때 이동한 숫자 중 최솟값을 구하면 됩니다.

풀이

사실 프로그래머스의 어떤 문제들은 시간제한이 없다는 점에서 백준에 비해 난이도가 굉장히 떨어지는 것 같다. 사실 틀렸습니다!보다 시간 초과가 훨씬(그것도 아주 많이) 무섭기 때문이다. 이 문제 또한 시간 복잡도를 계산해보면 한 4억번의 연산이 필요했지만, 시간 제한이 지정되지 않았기 때문에 일단 구현하였다. 이러한 회전 문제는 백준의 미세먼지 안녕!(17144)을 통해 풀어본 봐 있어서 어렵지 않게 구현해낼 수 있었다. 먼저 함수 매개변수로 행렬 자체가 주어지지 않았기 때문에 total이라는 변수를 선언하고, 하나씩 더해주면서 행렬을 만들었다. 그 다음에는 queries에 각 리스트를 스캔하며 x, y라는 변수를 시작하는 좌표로 설정하고, if문을 통하여 만약 x가 x2일 시(방향을 꺾어서 왼쪽으로 가야한다), y가 y2일 시(내려와야 한다), x가 x1이 아니고(x, y의 초기값이기 때문에)y가 y1일 시(올라가야 한다), 등으로 나눠서 tmp라는 graph의 요소를 복사한 리스트에다가 하나씩 이동하며 저장하였다. 여기서 새로운 리스트 tmp를 선언한 이유는 하나씩 요소가 밀리면서 그 다음 칸에 영향을 줄 수 있기 때문이고, copy를 사용하지 않은 이유는 copy를 사용하면 tmp는 graph가 참조하는 배열을 참조하게 됨으로, 참조하는 주소가 직접적으로 변화하기 때문에 하나씩 대입하면서 복사하였다. 각 x, y를 탐색하면서 최소 값을 max_cnt에 저장하고, 스캔이 끝나면 answer에다가 삽입하였다.

from typing import Any, Sequence
def solution(rows : int, columns : int, queries : Sequence) -> Sequence:
    answer = []
    graph = [[0 for _ in range(columns)]for _ in range(rows)]
    total = 1
    for i in range(rows):
      for j in range(columns):
        graph[i][j] = total
        total += 1
    for q in queries:
      for i in range(len(q)):
        q[i] -= 1
      tmp = [[graph[i][j]for j in range(columns)]for i in range(rows)]
      min_block = 10001
      x, y = q[0], q[1]
      while True:
        if min_block > graph[x][y]:
          min_block = graph[x][y]
        if x == q[0]+1 and y == q[1]:
          tmp[x-1][y] = graph[x][y]
          break
        if x != q[0] and y == q[1]:
          tmp[x-1][y] = graph[x][y]
          x -= 1
        elif x == q[2]:
          tmp[x][y-1] = graph[x][y]
          y -= 1
        elif y == q[3]:
          tmp[x+1][y] = graph[x][y]
          x += 1
        else:
          tmp[x][y+1] = graph[x][y]
          y += 1
      answer.append(min_block)
      graph = [[tmp[i][j]for j in range(columns)] for i in range(rows)]
    return answer
반응형