코딩테스트/백준

[백준 2164] 카드2

starcat37 2023. 5. 28. 18:07

1. 링크

https://www.acmicpc.net/problem/2164

2. 문제 설명

(1) 문제

N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다.

이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, 제일 위에 있는 카드를 바닥에 버린다. 그 다음, 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다.

예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나면, 남는 카드는 4가 된다.

N이 주어졌을 때, 제일 마지막에 남게 되는 카드를 구하는 프로그램을 작성하시오.

 

(2) 입력

첫째 줄에 정수 N(1 ≤ N ≤ 500,000)이 주어진다.

 

(3) 출력

첫째 줄에 남게 되는 카드의 번호를 출력한다.

3. 코드

#2164

from collections import deque

#입력받기
N = int(input())
cards = deque([i for i in range(1, N+1)])

#동작 정의
def act(cards):
    while (len(cards) != 1):
        cards.popleft()
        cards.append(cards[0])
        cards.popleft()
    print(cards[0])

act(cards)

4. 설명

우선, 문제에 주어진 동작을 구현해야 한다. 가장 위의 카드를 버리고 (cards.popleft()) 그 다음 위에 있는 카드를 가장 밑으로 놓는 것(cards.append(cards[0]), cards.popleft())이 일련의 동작이다. 해당 동작을 그대로 구현해 주면 된다.

그러나 주어진 카드 더미를 리스트로 구현해 del, pop 등의 메서드를 사용할 경우 시간 초과가 난다. 이는 파이썬 리스트가  이 문제에서 요구하는 큐 자료 구조를 구현하기에는 그리 효율적이지 않기 때문이다. 파이썬의 리스트는 다른 언어의 배열처럼 무작위 접근(random access)에 최적화되어, pop() 등은 시간 복잡도가 O(n)으로 매우 비효율적이다.

(참고: https://www.daleseo.com/python-queue/)

#2164

#입력받기
N = int(input())
cards = [i for i in range(1, N+1)]

#동작 정의
def act(cards):
    while (len(cards) != 1):
        del cards[0]
        cards.append(cards[0])
        del cards[0]
    print(cards[0])

act(cards)
#2164

#입력받기
N = int(input())
cards = [i for i in range(1, N+1)]

#동작 정의
def act(cards):
    while (len(cards) != 1):
        cards.pop(0)
        cards.append(cards[0])
        cards.pop(0)
    print(cards[0])

act(cards)

위 두 코드는 내가 시간초과를 경험한 코드이다. 이러한 시간 초과를 방지하기 위해, collections 모듈의 deque 함수를 불러와 popleft() 메서드를 사용할 수 있다. deque는 내부적으로 링크드 리스트로 구현되어 있기 때문에, popleft()의 시간복잡도는 O(1)이다. deque에 대한 더 자세한 내용은 아래 공식 레퍼런스에서 참고할 수 있다.

https://docs.python.org/3/library/collections.html#collections.deque

 

5. 배운 점

처음에 리스트로 구현할 때는 너무 쉽게 구현돼서 이게 실버 문제인가... 했는데 역시나 생각해야 할 거리가 있었다. 리스트가 무작위 접근에 최적화되어 있어서 pop이나 del의 시간복잡도가 O(n) 인 것도 처음 배웠고, 효율을 위해 deque를 사용할 수 있음을 배웠다. 기억해두면 유용하게 쓰일 것 같다.

'코딩테스트 > 백준' 카테고리의 다른 글

[COSE403] 1주차 연습 풀이와 설명 모음  (0) 2023.07.02
[백준 10250] ACM 호텔  (2) 2023.06.04
[백준 2108] 통계학  (0) 2023.05.21
[백준 1253] 좋다  (0) 2023.05.14
[백준 2018] 수들의 합  (0) 2023.05.14