[이코테 2021] 11. 이진 탐색(2/2)

Yewon Kim·2022년 7월 9일
0

CodingTest

목록 보기
15/22
post-thumbnail

🔊본 포스팅은 '(이코테 2021) 이것이 취업을 위한 코딩 테스트다 with 파이썬' 유튜브 강의를 수강하고 정리한 글입니다.

[문제1] 떡볶이 떡 만들기: 문제 설명

  • 오늘 동빈이는 여행 가신 부모님을 대신해서 떡집 일을 하기로 했습니다. 오늘은 떡볶이 떡을 만드는 날입니다. 동빈이네 떡볶이 떡은 재밌게도 떡볶이 떡의 길이가 일정하지 않습니다. 대신에 한 봉지 안에 들어가는 떡의 총 길이는 절단기로 잘라서 맞춰줍니다.
  • 절단기에 높이(H)를 지정하면 줄지어진 떡을 한 번에 절단합니다. 높이가 H보다 긴 떡은 H 위의 부분이 잘릴 것이고, 낮은 떡은 잘리지 않습니다.
  • 예를 들어 높이가 19,14,10,17cm인 떡이 나란히 있고 절단기 높이를 15cm로 지정하면 자른 뒤 떡의 높이는 15,14,10,15cm가 될 것입니다. 잘린 떡의 길이는 차례대로 4,0,0,2cm입니다. 손님은 6cm만큼의 길이를 가져갑니다.
  • 손님이 왔을 때 요청한 총 길이가 M일 때 적어도 M만큼의 떡을 얻기 위해 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하세요.

- 전형적인 이진 탐색 문제이자, 파라메트릭 서치 유형의 문제이다.
- 코딩 테스트나 프로그래밍 대회에서는 보통 파라메트릭 서치 유형은 이진 탐색을 이용하여 해결한다.

[Step 1] 시작점: 0, 끝점: 19, 중간점: 9
이때 필요한 떡의 크기: M=6이므로, 결과 저장
→ 0과 19 사이의 중간점 9를 절단기 높이 H로 설정하면 얻을 수 있는 떡의 합은 (10+6+1+8)=25이다. 필요한 떡의 길이가 6보다 크기 때문에 시작점을 증가시킨다.

[Step 2] 시작점: 10, 끝점: 19, 중간점: 14
이때 필요한 떡의 크기: M=6이므로, 결과 저장
→ 절단기 높이를 14로 설정하면 얻을 수 있는 떡의 합이 (5+1+3)=9이다. 여전히 필요한 떡의 길이인 6보다 크기 때문에 시작점을 증가시킨다.

[Step 3] 시작점: 15, 끝점: 19, 중간점: 17
이때 필요한 떡의 크기: M=6이므로, 결과 저장하지 않음
→ 필요한 떡의 길이인 6보다 작기 때문에 끝점을 감소시킨다.

[Step 4] 시작점: 15, 끝점: 16, 중간점: 15
이때 필요한 떡의 크기: M=6이므로, 결과 저장

- 이러한 이진 탐색 과정을 반복하면 답을 도출할 수 있다.
- 중간점의 값은 시간이 지날수록 '최적화된 값'이 되기 때문에, 과정을 반복하면서 얻을 수 있는 떡의 길이 합이 필요한 떡의 길이보다 크거나 같을 때마다 중간점의 값을 기록하면 된다.

# 떡의 개수(N)와 요청한 떡의 길이(M)을 입력
n, m = list(map(int, input().split(' ')))
# 각 떡의 개별 높이 정보를 입력
array = list(map(int, input().split()))

# 이진 탐색을 위한 시작점과 끝점 설정
start = 0
end = max(array)

# 이진 탐색 수행(반복적)
result = 0
while(start<=end):
	total = 0
    mid = (start+end)//2
    for x in array:
    	# 잘랐을 때의 떡의 양 계산
        if x>mid:
        	total += x-mid
        # 떡의 양이 부족한 경우 더 많이 자르기(왼쪽 부분 탐색)
        if total<m:
        	end = mid-1
        # 떡의 양이 충분한 경우 덜 자르기(오른쪽 부분 탐색)
        else:
        	result = mid  # 최대한 덜 잘랐을 때가 정답이므로, 여기에서 result에 기록
            start = mid+1
            
# 정답 출력
print(result)

[문제2] 정렬된 배열에서 특정 수의 개수 구하기: 문제 설명

  • N개의 원소를 포함하고 있는 수열이 오름차순으로 정렬되어 있습니다. 이때 이 수열에서 x가 등장하는 횟수를 계산하세요. 예를 들어 수열 {1,1,2,2,2,2,3}이 있을 때 x=2라면, 현재 수열에서 값이 2인 원소가 4개이므로 4를 출력한다.
  • 단, 이 문제는 시간 복잡도 O(logN)O(logN)으로 알고리즘을 설계하지 않으면 시간 초과 판정을 받습니다.

from bisect import bisect_left, bisect_right

# 값이 [left_value, right_value]인 데이터의 개수를 반환하는 함수
def count_by_range(array, left_value, right_value):
	right_index = bisect_right(array, right_value)
    left_index = bisect_left(array, left_value)
    return right_index-left_index
    
n, x = map(int, input().split())  # 데이터의 개수 N, 찾고자 하는 값 x 입력받기
array = list(map(int, input().split()))  # 전체 데이터 입력받기

# 값이 [x,x] 범위에 있는 데이터의 개수 계산
count = count_by_range(array,x,x)

# 값이 x인 원소가 존재하지 않는다면
if count == 0:
	print(-1)
# 값이 x인 원소가 존재한다면
else:
	print(count)

0개의 댓글