오늘의 문제 - 이분탐색
백준 10815번 - 숫자 카드
숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 N개를 가지고 있다. 정수 M개가 주어졌을 때, 이 수가 적혀있는 숫자 카드를 상근이가 가지고 있는지 아닌지를 구하는 프로그램을 작성하시오.
https://www.acmicpc.net/problem/10815
내 풀이 및 접근 방식
1. set 이용 방식
이전에 풀었던 문제여서 코드를 봤더니 왜 set으로 n_card를 묶어줬는지 기억나지 않았다. 원래의 나라면 set으로 묶지 않았을 것 같아서 n_card를 집합화하는 코드를 삭제해서 돌려봤더니 역시나 시간 초과가 발생했다. set은 꼭 필요한 코드였다.
import sys
N = sys.stdin.readline()
N_card = list(map(int, sys.stdin.readline().split()))
M = sys.stdin.readline()
M_card = list(map(int, sys.stdin.readline().split()))
N_card = set(N_card) # 이 코드 없으면 시간 초과
for m in M_card:
if m in N_card: # set 이용할 경우 O(1)이지만, 리스트 이용할 경우 O(n)
print(1, end=' ')
else:
print(0, end=' ')
set 집합의 경우 해시 테이블을 기반으로 하므로, 특정 요소를 찾는데 걸리는 시간 복잡도는 평균적으로 O(1)이다. 이는 리스트에서 특정 요소를 찾는 데 걸리는 시간 복잡도인 O(n)과 비교했을 때 시간 효율적임을 알 수 있다.
시간 복잡도: O(n+m)
- 집합 변환: O(n)
- 검색: O(m)
2. 이분 탐색
주제가 이분 탐색이라서 이분 탐색으로도 풀어봤다. 다행히 시간 초과가 나지 않는다.
import sys
n = int(sys.stdin.readline())
n_list = list(map(int, sys.stdin.readline().split()))
m = int(sys.stdin.readline())
m_list = list(map(int, sys.stdin.readline().split()))
n_list.sort()
answers = []
for mc in m_list:
answer = 0
start = 0
end = n-1
while start <= end:
mid = (start+end)//2
if n_list[mid] > mc:
end = mid - 1
elif n_list[mid] == mc:
answer = 1
break
else:
start = mid + 1
answers.append(answer)
for answer in answers:
print(answer, end=' ')
더 복잡해보이지만, m_card 리스트를 순회하며 각 카드 숫자와 일치하는 숫자가 n_card 리스트 중에 있는지 이분 탐색하는 것이다.
- n_card 리스트를 정렬한다.
- n_card 리스트의 처음 인덱스와 마지막 인덱스를 start와 end로 설정한다. answer 초기 값은 0(동일 숫자가 없는 경우)이다.
- 인덱스를 이분하고, 인덱스에 해당하는 n 카드 숫자가 현재의 m 카드 숫자보다 크면 end를 mid-1로 설정한다. 이는 작은 범위에서의 이분 탐색을 진행하기 위함이다.
반대로, n 카드 숫자가 현재의 m 카드 숫자보다 작다면 더 큰 범위에서의 이분 탐색을 진행하기 위해 start를 mid+1 값으로 설정한다.
만약, n 카드 숫자가 현재의 m 카드 숫자와 같다면 answer =1로 설정하여 동일 숫자가 있는 경우로 체크하고, 이분 탐색을 종료한다. - 각 숫자의 이분 탐색이 종료될 때마다 answer를 answers에 추가한다.
- answers 요소를 순서대로 출력한다.
시간 복잡도: O((n+m)logn)
- n_list.sort() 정렬: O(nlogn) (n: n_list 길이)
- 이진 탐색: O(mlogn) (m: m_list 길이, n: n_list 길이)
이분 탐색의 시간 복잡도는 O(logn)이고, 이를 m 번 수행하므로 O(mlogn)이다.
집합을 활용한 코드가 O(n+m) 시간 복잡도를 가지므로 이분 탐색을 이용한 코드보다 더 효율적이다.
회고
이분 탐색을 또 써먹었다. 굳
set도 dic과 마찬가지로 해시를 특징으로 해서 탐색 시간이 O(1)임을 알았다.
탐색과 같은 문제에 자주 사용하도록 하자.
'코테 스터디 99클럽' 카테고리의 다른 글
99클럽 코테 스터디 15일차 TIL + 완전탐색 (1) | 2024.08.06 |
---|---|
99클럽 코테 스터디 14일차 TIL + 이분탐색 (0) | 2024.08.05 |
99클럽 코테 스터디 12일차 TIL + 정렬 (0) | 2024.08.02 |
99클럽 코테 스터디 11일차 TIL + 정렬 (0) | 2024.08.02 |
99클럽 코테 스터디 10일차 TIL + 힙 (0) | 2024.08.01 |