https://www.acmicpc.net/problem/10816
10816번: 숫자 카드 2
첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,
www.acmicpc.net
문제
숫자 카드는 정수 하나가 적혀져 있는 카드이다. 상근이는 숫자 카드 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개의 수에 대해서, 각 수가 적힌 숫자 카드를 상근이가 몇 개 가지고 있는지를 공백으로 구분해 출력한다.
풀이
상근이가 가지고 있는 숫자카드를 오름차순으로 정렬하면 -10 -10 2 3 3 6 7 10 10 10 이다.
10 9 -5 2 3 4 5 -10 카드들이 상근이가 가지고 있는 카드 중 몇개씩 있는지 출력하는 문제이다.
M에 저장된 숫자들 하나씩 꺼내 상근이가 가지고 있는 숫자카드와 하나씩 비교하면 n^2의 시간복잡도인데,
N과 M의 최대값이 500,000이므로 500,000^2의 시간 O(n^2) 보다 낮은 시간복잡도로 풀어줘야한다.
( 500,000*(log_2 500,000) = 500,000 * 18.93~~ = 약 9백만 , 파이썬은 2천만번 -> 1초)
( 500,000^2 = 2500억 )
따라서 다른 방법으로 몇개씩 있는지 확인해줘야한다. 이 때 이분탐색(binary search)으로 해주면 log_2n으로 풀어줄 수 있다.
bisect은 배열 이진 분할 알고리즘을 포함하고있는 모듈이다. 아래의 두 함수를 사용하면 쉽게 풀어줄 수 있다.
1. bisect.bisect_left(a, x, lo=0, hi=len(a), *, key=None)
= a에 x를 삽입할 위치인 기존 항목 앞(왼쪽)을 반환한다.
2. bisect.bisect_right(a, x, lo=0, hi=len(a), *, key=None)
= a에 있는 x의 기존 항목 뒤(오른쪽)에 오는 삽입 위치를 반환한다.
상근이의 카드 -10 -10 2 3 3 6 7 10 10 10에서 숫자카드 3이 몇 개 있는지 확인할 때
bisect_left(nn, 3)은 nn에 3이 들어갈 수 있는 왼쪽 인덱스 3을 반환하고,
bisect_right(nn, 3)은 오른쪽 인덱스 5를 반환한다.
따라서 5 - 3 = 2, 상근이의 카드에 3의 개수는 2개임을 구해줄 수 있다.
import sys
import bisect
input = sys.stdin.readline
n= int(input())
nn = list(map(int, input().split()))
m= int(input())
mm = list(map(int, input().split()))
nn.sort()
for x in mm:
print(bisect.bisect_right(nn, x) - bisect.bisect_left(nn, x))