Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬으로 그리드 상자에서 공이 떨어지는 위치 찾기


문제 설명

m × n 크기의 격자 상자가 주어져 있다고 가정해 보겠습니다. 각 칸에는 대각선 방향으로 기울어진 판이 하나씩 놓여 있으며, 판은 왼쪽 위 → 오른쪽 아래 방향이거나 오른쪽 위 → 왼쪽 아래 방향입니다. 상자 맨 윗줄에서 공을 하나씩 넣었을 때, 그 공이 상자 바닥까지 무사히 도달하는지 확인해야 합니다.

격자는 행렬 형태로 주어집니다. 칸의 값이 1이면 해당 판은 왼쪽 위에서 오른쪽 아래로 향하고, 값이 -1이면 오른쪽 위에서 왼쪽 아래로 향합니다. n개의 공을 상자에 넣을 때, 각 공이 최종적으로 빠져나가는 열 번호를 구하되, 바닥에 도달하지 못하는 공은 -1로 표시해야 합니다.

파이썬으로 그리드 상자에서 공이 떨어지는 위치 찾기

3×3 격자 상자 예시

예를 들어 입력 행렬이 다음과 같다면,

111-1
-111-1
1-1-11
1-11-1

출력은 [-1, -1, -1, -1]이 됩니다. 즉, 어떤 공도 바닥에 도달하지 못합니다.

풀이 접근 방법

각 공의 위치를 한 행씩 내려가며 시뮬레이션하면 됩니다. 공은 현재 칸의 판 방향에 따라 좌우로 밀려나는데, 다음 두 가지 경우에는 바닥에 도달하지 못합니다.

  • 경계 밖으로 밀려나는 경우: 공이 격자의 왼쪽(x < 0) 또는 오른쪽(x ≥ j) 경계 밖으로 굴러 떨어지는 경우

  • V자 함정에 걸리는 경우: 인접한 두 칸의 판이 서로 마주 보게 배치되어(예: 1 다음에 -1) 공이 두 판 사이에 끼이는 경우

이를 의사 코드로 표현하면 다음과 같습니다.

  • i := 행렬 mat의 행 개수

  • j := 행렬 mat의 열 개수

  • res := 결과를 저장할 새로운 리스트

  • val을 0부터 j-1까지 반복합니다.

    • x := val (공이 시작되는 열)

    • r을 0부터 i-1까지 반복합니다.

      • s := mat[r][x] (현재 칸의 판 방향 저장)

      • x := x + mat[r][x] (판 방향에 따라 공을 이동)

      • 만약 x < 0 또는 x ≥ j 또는 mat[r][x] ≠ s라면:

        • res의 끝에 -1을 추가합니다.

        • 반복문을 탈출합니다.

    • 안쪽 반복문이 break 없이 정상 종료되면, res의 끝에 x를 추가합니다.

  • res를 반환합니다.

참고로 파이썬의 for-else 문법에서 else 블록은 반복문이 break 없이 모두 실행된 경우에만 수행됩니다. 따라서 공이 끝까지 내려간 경우에만 else 블록이 실행되어 최종 열 번호가 기록됩니다.

예제 코드

아래 구현을 통해 더 자세히 이해해 보겠습니다.

def solve(mat):
    i, j = map(len, (mat, mat[0]))
    res = []
    for val in range(j):
        x = val
        for r in range(i):
            s = mat[r][x]
            x += mat[r][x]
            if x < 0 or x >= j or mat[r][x] != s:
                res += [-1]
                break
        else:
            res += [x]
    return res

print(solve([[1, 1, 1, -1], [-1, 1, 1, -1], [1, -1, -1, 1],[1, -1, 1, -1] ]))

입력

[[1, 1, 1, -1], [-1, 1, 1, -1], [1, -1, -1, 1],[1, -1, 1, -1] ]

출력

[-1, -1, -1, -1]

복잡도 분석

시간 복잡도는 O(m × n)입니다. 각 공마다 최대 m개의 행을 거치며, 총 n개의 공을 처리하기 때문입니다. 공간 복잡도는 결과 리스트를 제외하면 O(1)로, 추가 메모리 사용 없이 해결할 수 있습니다.