10815 - 숫자 카드
INDEX
문제 설명
숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 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차 제출 코드
from sys import stdin
n = int(stdin.readline())
arr = list(map(int, stdin.readline().split()))
m = int(stdin.readline())
cmp_arr = list(map(int, stdin.readline().split()))
result = ''
for i in range(m):
if cmp_arr[i] in arr:
result += '1 '
else:
result += '0 '
print(result)
처음에 제출한 코드는 위와 같다.
배열(arr, cmp_arr) 입력받고 cmp_arr배열 인덱스를 통해 순회하며 원소가 arr 배열 내 같은 원소가 있는지 확인하여 분기하였다.
위 코드는 테스트케이스는 정상적으로 만족하지만 시간초과가 떳다.
이후 문제를 다시 살펴보았다.
상근이는 150만개의 카드를 가질 수 있으며 비교해야 할 카드도 150만개다.
따라서, 단순히 비교해도 약 250000000000번의 연산이 필요하다.
파이썬은 1초에 1000만 ~ 1억번의 연산이 가능하다. 위 계산대로라면 최소 250초가 걸린다..
시간 제한이 2초이므로 효율적 알고리즘을 찾아야 한다.
2차 제출 코드
from sys import stdin
'''
숫자 카드 N개 가지고 있음.
정수 M개가 주어졌을 때 이 수가 있는 수인지 아닌지 구해라.
'''
n = int(stdin.readline())
arr = list(map(int, stdin.readline().split()))
m = int(stdin.readline())
arr.sort() # 이진 탐색을 위한 정렬
for key in list(map(int, stdin.readline().split())):
left = 0
right = n-1
while True:
if left > right:
print(0, end=' ')
break
mid = (left + right) // 2
if arr[mid] == key:
print(1, end=' ')
break
elif arr[mid] > key:
right = mid - 1
else:
left = mid + 1
두번째 제출한 코드는 시간복잡도를 고려한 효율적 탐색을 위해 이진 탐색을 이용하였다. 그 결과 정답으로 처리되었다.
문제풀이
이번 문제는 시간복잡도를 고려하여 풀어야하는 문제다.
입력값 N과 M은 1 <= N,M<= 500,000
의 범위를 갖는다. 따라서 비교횟수는 1~250,000,000,000번의 범위를 갖는다.
파이썬은 1초에 약 1000만 ~ 1억번의 연산이 가능하므로 최소 250초 최대 2500초의 시간이 소요된다.
따라서, 보다 효율적으로 탐색할 수 있는 알고리즘이 필요하다.
필자는 이진탐색 알고리즘을 활용하여 문제를 풀었다.
제출 코드에서 이진탐색 부분을 살펴보도록 한다.
while True:
if left > right: # left값이 right보다 큰 경우
print(0, end=' ')
break
mid = (left + right) // 2 # mid값 설정
if arr[mid] == key: # 비교 배열에서 뽑은 원소가 현재 배열의 중간값과 동일한 경우
print(1, end=' ')
break
elif arr[mid] > key: # 중간값이 찾고자 하는 값보다 큰 경우 , right 값을 변경하여 범위 수정
right = mid - 1
else:
left = mid + 1 # 중간값이 찾고자 하는 값보다 작은 경우, left 값을 변경하여 범위 수정
'Algorithm & SQL > Baekjoon' 카테고리의 다른 글
[Algorithm] [Python] 백준/BOJ - 11866 _ 요세푸스 문제0 (0) | 2020.05.18 |
---|---|
[Algorithm] [Python] 백준/BOJ - 2309 _ 일곱 난쟁이 (0) | 2020.05.18 |
[Algorithm] [Python] 백준/BOJ - 2455 _ 지능형 기차 (0) | 2020.05.15 |
[Algorithm] [Python] 백준/BOJ - 5532 _ 방학 숙제 (0) | 2020.05.14 |
[Algorithm] [Python] 백준/BOJ - 2822 _ 점수계산 (0) | 2020.05.14 |