백준 10815번 숫자 카드

이재원·2024년 2월 28일

문제


숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 N개를 가지고 있다. 정수 M개가 주어졌을 때, 이 수가 적혀있는 숫자 카드를 상근이가 가지고 있는지 아닌지를 구하는 프로그램을 작성하시오.

입력


첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다. 두 숫자 카드에 같은 수가 적혀있는 경우는 없다.

셋째 줄에는 M(1 ≤ M ≤ 500,000)이 주어진다. 넷째 줄에는 상근이가 가지고 있는 숫자 카드인지 아닌지를 구해야 할 M개의 정수가 주어지며, 이 수는 공백으로 구분되어져 있다. 이 수도 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다.

출력


첫째 줄에 입력으로 주어진 M개의 수에 대해서, 각 수가 적힌 숫자 카드를 상근이가 가지고 있으면 1을, 아니면 0을 공백으로 구분해 출력한다.

예제 입력 1

5
6 3 2 10 -10
8
10 9 -5 2 3 4 5 -10

예제 출력 1

1 0 0 1 1 0 0 1

- 내가 처음에 푼 방법.

import sys

input = sys.stdin.readline

n = int(input())
nlist = list(map(int, input().split()))

m = int(input())
mlist = list(map(int, input().split()))

for i in mlist:
    if i in nlist:
        print(1, end=" ")
    else:
        print(0, end=" ")

for문과 if문을 사용해서 원소를 하나씩 비교하면 되겠다고 생각하여 풀었는데 시간초과가 발생했다. 그래서 백준 하단에 알고리즘 분류 카테고리 목록을 봤는데 이분탐색이 있어서 이분 탐색 방식으로 해결해서 풀었다.

- 두번째 푼 방식

import sys

input = sys.stdin.readline

n = int(input())
nlist = sorted(list(map(int, input().split())))

m = int(input())
mlist = list(map(int, input().split()))

for i in mlist:
    low, high = 0, n - 1
    check = False
    while low <= high:
        mid = (low + high) // 2
        if nlist[mid] < i:
            low = mid + 1
        elif nlist[mid] > i:
            high = mid - 1
        elif nlist[mid] == i:
            check = True
            break
    print(1 if check else 0, end=" ")

이분탐색으로 해결했을 때 시간이 단축 될 줄은 알았지만 시간이 3132ms가 나와 더 빠른 문제풀이 방식이 있을 것 같았고 다른 분들의 코드를 보면서 빠른 코드 위주로 확인을 해보았다.

- 마지막에 푼 방식

import sys

input = sys.stdin.readline

n = int(input())
nlist = set(list(map(int, input().split())))

m = int(input())
mlist = list(map(int, input().split()))

for i in mlist:
    if i in nlist:
        print(1, end=" ")
    else:
        print(0, end=" ")

다른 사람들의 풀이법을 찾아보다가 시간이 적게 나온 사람들 것을 봤는데 나랑 코드가 set을 썼다는 것을 제외하고 큰 차이가 없었다. 내가 아는 set은 순서와 중복이 없는 자료구조로 알고있는데 카드에는 중복이 없다고 나와있었다. 근데 시간면에서 엄청 큰 차이가 있어 찾아보니 set과 list는 내부적으로 데이터를 저장하고 검색하는 방식이 다르기 때문에, 특히 원소의 존재 여부를 확인할 때 그 차이가 많이 난다고한다.

  • 그 이유는 set은 해시테이블 기반으로 구성되어있어 평균적인 경우 원소의 존재여부를 확인하는데O(1) 시간이 걸린다고한다.
  • list는 배열 기반으로 구현되어있어 특정 값의 존재 여부를 확인하려면 리스트 전체를 순차적으로 탐색해야한다. 최악의 경우 O(n)의 시간이 걸려 set을 사용하지 않았을 때 시간초과가 발생했던 것이다.

결론

대규모 데이터에서 원소의 존재 여부만을 빠르게 확인하고 싶다면 set을 사용하자!!
++ 파이썬에서 딕셔너리도 해시테이블 기반

첫번째 코드 : 시간초과
두번째 코드 : 메모리 113108KB 시간 3132ms
세번째 코드 : 메모리 125632KB 시간 612ms
https://www.acmicpc.net/problem/10815 백준 숫자카드 10815번

profile
최고가 되기 위한 여정

0개의 댓글