ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준 BOJ] 1158번 요세푸스 문제 (파이썬 Python)
    코딩/알고리즘 - 백준 2022. 8. 8. 16:23

    문제 설명

     

    1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 K (≤ N)가 주어진다.

     

    이제 순서대로 K번째 사람을 제거한다.

    한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속된다.

     

    원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다.

    예를 들어 (7, 3)-요세푸스 순열은 <3, 6, 2, 7, 5, 1, 4>이다.

     

     

    N과 K가 주어지면 (N, K)-요세푸스 순열을 구하는 프로그램을 작성하시오.

     

     

    예제 입력1

    7 3

     

     

     

     

    코드 및 풀이

     

     

     

    처음에는 리스트를 이용하여 풀이를 진행했다. (아래 코드)

     

    리스트는 더 오래걸린다는 것을 알고 있었지만

    단순히 양쪽 끝 인덱스만 사용하기 때문에 혹시나 괜찮지 않을까라고 생각하였지만

    시간 초과가 발생했다.

     

    import sys
    
    input = sys.stdin.readline
    
    n, k = map(int, input().split())
    arr = [i+1 for i in range(n)]
    ans = []
    
    while arr:
        for i in range(k-1):
            arr.append(arr[0])
            del arr[0]
    
        ans.append(arr[0])
        del arr[0]
    
    print("<", end = '')
    print(*ans, sep = ', ', end = '')
    print(">")
    
    
    # time over

     

     

     

     

    정답 코드

    import sys
    from collections import deque
    
    input = sys.stdin.readline
    
    n, k = map(int, input().split())
    
    people = [i+1 for i in range(n)]
    people = deque(people)
    
    result = []
    while people:
        people.rotate(-(k-1))
        result.append(people.popleft())
    
    print(str(result).replace('[', '<').replace(']', '>'))

     

    deque 모듈을 사용한 정답코드이다.

     

    먼저 주어진 n까지의 수열을 만들어 준 뒤, deque으로 바꿔준다.

    people = [1, 2, 3, 4, 5, 6, 7]    << deque

     

    reotate()는 덱을 주어진 수만큼 회전하는 함수이다.

    양수면 오른쪽으로, 음수이면 왼쪽으로 회전시킨다.

     

    주어진 수가 3이기 때문에(예제 1) 하나 적은 2만큼 회전 시킨 후

    해당 숫자를 뽑아 정답 배열에 추가한다.

     

    [1, 2, 3, 4, 5, 6, 7]   (2회 회전)>>  [3, 4, 5, 6, 7, 1, 2]

     

    (pop)>>  people = [4, 5, 6, 7, 1, 2], result = [3]

     

     

    해당 과정을 원래 수열이 빌 때까지 반복한다.

     

     

    출력은 리스트(덱)를 문자열로 바꾼 후

    replace 함수를 이용해 문제에서 요구하는 형식으로 바꿔준다.

     

     

     

     

    다른 표현

    import sys
    from collections import deque
    
    input = sys.stdin.readline
    
    n, k = map(int, input().split())
    people = deque()
    for i in range(1, n+1):
        people.append(i)
    result = []
    
    while people:
      for i in range(k-1):
          people.append(people.popleft())
          # people.rotate(-1)
    
    print("<", end = '')
    print(*ans, sep = ', ', end = '')
    print(">")
    # print(str(result).replace('[', '<').replace(']', '>'))

     

    풀이 방식을 같이 하는 다른 표현도 가능하다.

    rerotate 대신 pop과 append를 사용하고,

     

    print 방식도 위와 같이 바꿔볼 수 있다.

    print문 안의 리스트 앞에 * (Asterisk)를 써주면 리스트를 한 줄로 출력할 수 있게 해준다. (list unpacking)

     

     

     

     

    다른 풀이 (deque 모듈 사용 x)

     

    import sys
    
    input = sys.stdin.readline
    
    n, k = map(int, input().split())
    arr = [i for i in range(1,n+1)]
    ans = []
    num = 0
    
    for i in range(n):
        num+=(k-1)
        
        if num >= len(arr):
            num %= len(arr)
            
        ans.append(str(arr[num]))
        arr.pop(num)
    
    print("<",', '.join(ans),">", sep="")

     

    deque 모듈을 사용하지 않고도 가능하다.

     

    기존 배열을 삭제(pop), 정답 배열을 추가하는 과정에서

    num 변수를 선언해 인덱스로 접근한다.

     

    num이 배열보다 커질 경우 나머지 연산 (% )을 이용해

    num을 수정해 준다.

     

    출력 과정에서 join 함수를 사용하기 때문에

    정답 리스트(ans)에 원소를 추가하는 과정에서 str()을 이용해

    문자열로 바꿔서 추가한다.

     

     

     

    참고) 덱과 리스트의 시간 복잡도 비교

    리스트
    시간 복잡도 사진1 (아래 왼쪽) 사진2 (아래 오른쪽)

     

     

     

    리스트의 시간 복잡도(왼쪽)    덱의 시간 복잡도(오른쪽)

     

     

     

     

     

     

     

     

    참조 및 출처

    deque 모듈이용 풀이: https://velog.io/@thguss/%EB%B0%B1%EC%A4%80-1158.-%EC%9A%94%EC%84%B8%ED%91%B8%EC%8A%A4-with.-Python-%ED%81%90-%EB%AC%B8%EC%A0%9C%EC%97%90%EC%84%9C-deque%EB%8A%94-%ED%95%84%EC%88%98-%EB%B3%84%EA%BC%AC%EB%A6%AC-%EB%95%85%EB%95%85

    모듈 이용 x: https://imzzan.tistory.com/2

    리스트와 덱의 시간 복잡도: https://wellsw.tistory.com/122

     

     

     

     

     

    문제 출처: https://www.acmicpc.net/problem/1158

     

    1158번: 요세푸스 문제

    첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 5,000)

    www.acmicpc.net

     

    댓글

Designed by Tistory.