[프로그래머스/Lv.0] 안전지대 | 파이썬

문제

https://school.programmers.co.kr/learn/courses/30/lessons/120866

다음 그림과 같이 지뢰가 있는 지역과 지뢰에 인접한 위, 아래, 좌, 우 대각선 칸을 모두 위험지역으로 분류합니다.

지뢰는 2차원 배열 board에 1로 표시되어 있고 board에는 지뢰가 매설 된 지역 1과, 지뢰가 없는 지역 0만 존재합니다.
지뢰가 매설된 지역의 지도 board가 매개변수로 주어질 때, 안전한 지역의 칸 수를 return하도록 solution 함수를 완성해주세요.

 

제한사항

  • board는 n * n 배열입니다.
  • 1 ≤ n ≤ 100
  • 지뢰는 1로 표시되어 있습니다.
  • board에는 지뢰가 있는 지역 1과 지뢰가 없는 지역 0만 존재합니다.

 

입출력 예

입출력 예 #1

  • (3, 2)에 지뢰가 있으므로 지뢰가 있는 지역과 지뢰와 인접한 위, 아래, 좌, 우, 대각선 총 8칸은 위험지역입니다. 따라서 16을 return합니다.

입출력 예 #2

  • (3, 2), (3, 3)에 지뢰가 있으므로 지뢰가 있는 지역과 지뢰와 인접한 위, 아래, 좌, 우, 대각선은 위험지역입니다. 따라서 위험지역을 제외한 칸 수 13을 return합니다.

입출력 예 #3

  • 모든 지역에 지뢰가 있으므로 안전지역은 없습니다. 따라서 0을 return합니다.

 

나의 풀이

def solution(board):
    n = len(board)
    moves = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
    answer = 0
    
    for i in range(n):
        for j in range(n):
            if board[i][j] == 1:
                for dx, dy in moves:
                    nx, ny = i + dx, j + dy
                    if 0 <= nx < n and 0 <= ny < n and board[nx][ny] != 1:
                        board[nx][ny] = -1
    
    for line in board:
        answer += line.count(0)
                
    return answer

좌표 움직임을 `moves`에 미리 생성해놓고, 지뢰가 있는 경우 `board`의 범위 안에서 이동하면서 위험지역을 `-1`로 표시했다.

최종적으로 지뢰가 위치한 `1`, 지뢰 인접 지역인 `-1`을 제외하고 안전지역인 `0`의 개수만 카운트해서 출력한다.

 

다른 사람의 풀이1

def solution(board):
    n = len(board)
    answer = 0
    
    for i in range(n):
        for j in range(n):
            if board[i][j] == 1:
                for nx in range(max(0, i - 1), min(n, i + 2)):
                    for ny in range(max(0, j - 1), min(n, j + 2)):
                        if board[nx][ny] != 1:
                            board[nx][ny] = -1
    
    for line in board:
        answer += line.count(0)     
                
    return answer

내 풀이와 비슷한 방식인데 좌표 내에서 이동하기 위해 조건문을 사용하는 것이 아니라

`max, min`을 이용해서 처음부터 이동 범위를 제한했다.

 

다른 사람의 풀이2

def solution(board):
    n = len(board)
    danger = set()
    
    for i in range(n):
        for j in range(n):
            if board[i][j] == 1:
                danger.update((i + dx, j + dy) for dx in [-1, 0, 1] for dy in [-1, 0, 1])
                
    return n * n - sum(0 <= x < n and 0 <= y < n for x, y in danger)

`set()`에 위험 지역을 모두 표시하는데, 이때 한 번에 여러 개의 요소를 추가할 수 있는 `set.update()`를 이용한다.

일단 지뢰에 인접한 모든 지역을 `set()`에 저장한 후, 카운트 하는 시점에 조건문으로 좌표를 벗어난 지역을 제외한다.

 

회고

개발 시작하고 6개월 쯤에 처음 도전했던 문제인데 그때는 손도 못 댈 정도로 어려워했던 기억이 난다.

지금은 문제 보고 바로 풀 수 있어서 새삼 많이 발전했다는 생각이 든다 ㅎㅎ