문제

[프로그래머스] 거리두기 확인하기 (LV. 2)

요약

  1. 5X5 크기의 대기실에 사람들이 대기한다.
  2. 맨해튼 거리 2 이하로 앉지 않는다.
  3. 단, 응시자 사이가 파티션으로 막혀 있다면 허용한다.

분류

  • 배열
  • (dx/dy)

풀이

1. 내 풀이

  • 발상 : 그냥 하라는 거 그대로 하는 직관적 풀이다. 사람(P) 의 위치를 모두 찾는다. 2중 FOR 문으로 모든 경우의 수를 순회하며 조건을 만족시키는지 검사한다.
  • P의 인덱스를 순회할 때, 개선이 가능하지만 5X5 배열으로 입력의 크기가 한정적이어서 그냥 놔뒀다.


  • 1차 풀이

      def isNear(a, b, arr):
          y1, x1 = a
          y2, x2 = b
          dis = abs(x1 - x2) + abs(y1 - y2)
          if dis == 1:
              return False
          elif dis == 2 :
              if x1 == x2 or y1 == y2:
                  return arr[(y1 + y2) // 2][(x1 + x2) // 2] == 'X'
              return arr[y1][x2] == 'X' and arr[y2][x1] == 'X'
          else:
              return True
    
    
      def solution(places):
          answer = []
          cur = 0
    
          for place in places:
              cur += 1
              arr = []
              for i in range(5):
                  for j in range(5):
                      if place[i][j] == 'P':
                          arr.append([i, j])
              key = False
              for i in range(len(arr) - 1):
                  for j in range(i + 1, len(arr)):
                      if not isNear(arr[i], arr[j], place):
                          answer.append(0)
                          key = True
                          break
                  if key : break
    
              if len(answer) != cur:
              answer.append(1)
          print(answer)
          return answer
    


  • 2차 풀이 (리팩터링을 진행)

    ```python
    for i in range(5):
        for j in range(5):
            if place[i][j] == 'P':
                arr.append([i, j])
    ```
    
    이 코드를
    
    ```python
    arr = [(i, j) for i in range(5) for j in range(5) if place[i][j] == 'P']
    ```
    
    이렇게 한 줄로 개선한다.
    
    \+ 알아두기
    - 파이썬에서 커스텀 에러를 raise 하는 방법으로 2중 이상의 for문을 한 번에 break 할 수 있다.
        ```python
        class BreakLoop(Exception):
            pass
    
        def solution(places):
            answer = []
    
            for place in places:
                arr = [(i, j) for i in range(5) for j in range(5) if place[i][j] == 'P']
                try:
                    for i in range(len(arr) - 1):
                        for j in range(i + 1, len(arr)):
                            if not is_near(arr[i], arr[j]):
                                answer.append(0)
                                raise BreakLoop  # Custom exception to break out of nested loops
                    else:
                        answer.append(1)
                except BreakLoop:
                    pass
    
            return answer
    
        ```
    


  • 최종 코드 - all 함수 기억하자 (모두 true 면 true 반환, 아니면 false) - * (asterisk) 를 활용한 언패킹 - 파이써닉 코드…?

    ```python
    def is_near(y1, x1, y2, x2, place):
        dis = abs(x1 - x2) + abs(y1 - y2)
        return dis > 1 and (dis != 2 or (x1 == x2 or y1 == y2) and place[(y1 + y2) // 2][(x1 + x2) // 2] == 'X' or place[y1][x2] == place[y2][x1] == 'X')
    
    
    def check(place):
            arr = [(i, j) for i in range(5) for j in range(5) if place[i][j] == 'P']
            return all(is_near(*arr[i], *arr[j], place) for i in range(len(arr) - 1) for j in range(i + 1, len(arr)))
    
    def solution(places):
        return [1 if check(place) else 0 for place in places]
    
    ```
    


2. 프로그래머스 좋아요가 많았던 풀이

  • dxdy 코드가 많아서 굳이 안 가져왔다. (dxdy를 활용할 만한 문제인지 모르겠다.)