[이진 탐색의 핵심 이론]
시간 제한 2초, 실버 IV, 백준 1920번
N개의 정수 A[1], A[2], …, A[N]이 주어져 있을 때, 이 안에 X라는 정수가 존재하는지 알아내는 프로그램을 작성하시오.
첫째 줄에 자연수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 줄에는 N개의 정수 A[1], A[2], …, A[N]이 주어진다. 다음 줄에는 M(1 ≤ M ≤ 100,000)이 주어진다. 다음 줄에는 M개의 수들이 주어지는데, 이 수들이 A안에 존재하는지 알아내면 된다. 모든 정수의 범위는 -231 보다 크거나 같고 231보다 작다.
5 # 데이터 개수 4 1 5 2 3 5 # 찾아야 할 숫자 개수 1 3 7 9 5
M개의 줄에 답을 출력한다. 존재하면 1을, 존재하지 않으면 0을 출력한다.
1 1 0 0 1
N(수 개수 저장)
A(수 데이터 리스트 저장)
A 리스트 정렬
M(탐색할 숫자 개수 저장)
target_list(탐색할 수 데이터 리스트 저장)
for M 개수 만큼 반복:
target(찾아야 하는 수)
# 이진 탐색 시작
start(시작 인덱스)
end(종료 인덱스)
while 시작 인덱스 <= 종료 인덱스:
midi(중간 인덱스)
midv(중앙값)
if 중앙값 > target:
종료 인덱스 = 중간 인덱스 - 1
elif 중앙값 < target:
시작 인덱스 = 중간 인덱스 + 1
else:
찾았음, 반복문 종료
if(찾았음) 1 출력
else 0 출력
N = int(input())
A = list(map(int, input().split()))
A.sort()
M = int(input())
target_list = list(map(int, input().split()))
for i in range(M):
find = False
target = target_list[i]
# 이진 탐색 시작
start = 0
end = len(A) - 1
while start <= end:
midi = int((start + end) / 2)
midv = A[midi]
if midv > target:
end = midi - 1
elif midv < target:
start = midi + 1
else:
find = True
break
if find:
print(1)
else:
print(0)
시간 제한 2초, 실버 I, 백준 2343번
강토는 자신의 기타 강의 동영상을 블루레이로 만들어 판매하려고 한다. 블루레이에는 총 N개의 강의가 들어가는데, 블루레이를 녹화할 때, 강의의 순서가 바뀌면 안 된다. 순서가 뒤바뀌는 경우에는 강의의 흐름이 끊겨, 학생들이 대혼란에 빠질 수 있기 때문이다. 즉, i번 강의와 j번 강의를 같은 블루레이에 녹화하려면 i와 j 사이의 모든 강의도 같은 블루레이에 녹화해야 한다.
강토는 이 블루레이가 얼마나 팔릴지 아직 알 수 없기 때문에, 블루레이의 개수를 가급적 줄이려고 한다. 오랜 고민 끝에 강토는 M개의 블루레이에 모든 기타 강의 동영상을 녹화하기로 했다. 이때, 블루레이의 크기(녹화 가능한 길이)를 최소로 하려고 한다. 단, M개의 블루레이는 모두 같은 크기이어야 한다.
강토의 각 강의의 길이가 분 단위(자연수)로 주어진다. 이때, 가능한 블루레이의 크기 중 최소를 구하는 프로그램을 작성하시오.
첫째 줄에 강의의 수 N (1 ≤ N ≤ 100,000)과 M (1 ≤ M ≤ N)이 주어진다. 다음 줄에는 강토의 기타 강의의 길이가 강의 순서대로 분 단위로(자연수)로 주어진다. 각 강의의 길이는 10,000분을 넘지 않는다.
9 3 # 레슨 수, 블루레이 개수 1 2 3 4 5 6 7 8 9
첫째 줄에 가능한 블루레이 크기중 최소를 출력한다.
17
[이진 탐색 수행]
N(레슨 개수 저장) M(블루레이 개수 저장)
A(기타 레슨 데이터 저장 리스트)
start(시작 인덱스)
end(종료 인덱스)
for A 리스트 탐색:
시작 인덱스 저장(A 리스트 중 최댓값)
종료 인덱스 저장(A 리스트의 총합)
while 시작 인덱스 <= 종료 인덱스:
middle(중간 인덱스)
sum(레슨 합)
count(현재 사용한 블루레이 개수)
for N의 개수만큼 반복:
if sum + 현재 레슨 시간 > 중간 인덱스:
count 값을 올리고 sum을 0으로 리셋하기
# 현재 블루레이에 저장할 수 없어 새로운 블루레이로 교체한다는 의미
sum에 현재 레슨 시간값 더하기
sum이 0이 아니면 마지막 블루레이가 필요하므로 count값 올리기
if count > M: # 중간 인덱스 값으로 모든 레슨 저장 불가능
시작 인덱스 = 중앙 인덱스 + 1
else: # 중간 인덱스 값으로 모든 레슨 저장 가능
종료 인덱스 = 중앙 인덱스 - 1
시작 인덱스 출력
N, M = map(int, input().split())
A = list(map(int, input().split()))
start = 0
end = 0
for i in A:
if start < i:
start = i # 레슨 최댓값을 시작 인덱스로 저장
end += i # 모든 레슨의 총합을 종료 인덱스
while start <= end:
middle = int((start + end) / 2)
sum = 0
count = 0
for i in range(N): # 중간값으로 모든 레슨을 저장할 수 있는지 확인
if sum + A[i] > middle:
count += 1
sum = 0
sum += A[i]
if sum != 0:
count += 1
if count > M:
start = middle + 1
else:
end = middle - 1
print(start)
시간 제한 2초, 골드 II, 백준 1300번
세준이는 크기가 N×N인 배열 A를 만들었다. 배열에 들어있는 수 A[i][j] = i×j 이다. 이 수를 일차원 배열 B에 넣으면 B의 크기는 N×N이 된다. B를 오름차순 정렬했을 때, B[k]를 구해보자.
배열 A와 B의 인덱스는 1부터 시작한다.
첫째 줄에 배열의 크기 N이 주어진다. N은 10^5보다 작거나 같은 자연수이다. 둘째 줄에 k가 주어진다. k는 min(10^9, N^2)보다 작거나 같은 자연수이다.
3 7
B[k]를 출력한다.
6
N(리스트의 크기) K(구하고자 하는 index)
start(시작 인덱스 = 1)
end(종료 인덱스 = K)
# 이진 탐색 수행
while 시작 인덱스 <= 종료 인덱스:
middle(중간 인덱스)
cnt(중앙값보다 작은 수)
# 중앙값보다 작은 수 계산
for i는 1~N:
cnt에 중앙 인덱스를 i로 나눈 값과 N 중 작은 값을 더함
if cnt < K: # 현재 중앙값보다 작은 수의 개수가 K보다 작음
시작 인덱스 = 중앙 인덱스 + 1
else: # 현재 중앙값보다 작은 수의 개수가 K보다 크거나 같음
종료 인덱스 = 중앙 인덱스 - 1
정답 변수에 중앙값 저장
정답 출력
N = int(input())
K = int(input())
start = 1
end = K
ans = 0
# 이진 탐색 수행
while start <= end:
middle = int((start + end) / 2)
cnt = 0
# 중앙값보다 작은 수 계산
for i in range(1, N+1):
cnt += min(int(middle / i), N) # 작은 수 카운트 핵심 로직
if cnt < K:
start = middle + 1
else:
ans = middle
end = middle - 1
print(ans)