문제 설명
리스트 L 과, 그 안에서 찾으려 하는 원소 x 가 인자로 주어지고, 또한 탐색의 대상이 되는 리스트 내에서의 범위 인덱스가 l 부터 u 까지로 (인자로) 정해질 때, x 와 같은 값을 가지는 원소의 인덱스를 리턴하는 함수 solution() 을 완성하세요. 만약 리스트 L 안에 x 와 같은 값을 가지는 원소가 존재하지 않는 경우에는 -1 을 리턴합니다. 리스트 L 은 자연수 원소들로 이루어져 있으며, 크기 순으로 정렬되어 있다고 가정합니다. 또한, 동일한 원소는 두 번 이상 나타나지 않습니다.
인덱스 범위를 나타내는 l 과 u 가 인자로 주어지는 이유는, 이 함수를 재귀적인 방법으로 구현하기 위함입니다. 빈 칸에 알맞은 내용을 채워서 재귀 함수인 solution() 을 완성하세요.
예를 들어,
L = [2, 3, 5, 6, 9, 11, 15], x = 6, l = 0, u = 6의 인자들이 주어지면, L[3] == 6 이므로 3 을 리턴해야 합니다.
또 다른 예로,
L = [2, 5, 7, 9, 11], x = 4, l = 0, u = 4로 주어지면, 리스트 L 내에 4 의 원소가 존재하지 않으므로 -1 을 리턴해야 합니다.
Python 동작 코드
def rec_bin_search(L, x, l, u):
if l>u:
return -1
mid = (l + u) // 2
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1)
else:
return rec_bin_search(L, x, mid+1, u)
Q1. if 조건문에서 l>u가 아닌 x not in L 을 써도 상관 없지 않나?
A2. 결과값만 본다면 똑같은 결과가 나온다. 하지만 효율성이 떨어진다. 파이썬의 포함 연산자는 O(n)의 복잡도를 가진다. 이진탐색을 하는 이유가 복잡도를 O(n)에서 O(log n)으로 줄이기 위함인데, x not in L을 쓰는 것은 효율적이지 않은 방식이다.
Q2. 왜 재귀함수에서 rec_bin_search 부분에서 l 대신 mid가 아닌 mid+1, u 대신 mid가 아닌 mid-1이 들어갔을까?
A2. mid를 인덱스로 갖는 값 자체가 조건 연산에서 이미 작거나 크다고 나와있기 때문에 그 값보다 작다면 mid의 인덱스보다 한칸 크거나 작은 인덱스를 가지는 것이 무한 루프에 빠지지 않게 한다.
한줄한줄 따라가는 시뮬레이션
case1. 리스트 L안에 찾으려는 원소x가 존재하는 경우
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31] 이라 하고, 이때의 rec_bin_search(L, 17, 0, 10)을 실행을 시뮬레이션 해보자.
#Step1
def rec_bin_search(L, x, l, u):
if l>u: # l=0, u=10, 0<10이므로 조건만족x
return -1
mid = (l + u) // 2 # mid = (0 + 10)//2 => 5
# l=0, u=10, x=17, L[mid] = 14
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1)
else:
return rec_bin_search(L, x, mid+1, u) # l=(mid+1)=6, u=10, x=17
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31]
#Step2
def rec_bin_search(L, x, l, u):
if l>u: # l=6, u=10, 6<10이므로 조건만족x
return -1
mid = (l + u) // 2 # mid = (6 + 10)//2 => 8
# l=6, u=10, x=17, L[mid] = 24
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1) # l=6, u=(mid-1)=7, x=17
else:
return rec_bin_search(L, x, mid+1, u)
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31]
#Step3
def rec_bin_search(L, x, l, u):
if l>u: # l=6, u=7, 6<7이므로 조건만족x
return -1
mid = (l + u) // 2 # mid = (6 + 7)//2 => 6
# l=6, u=7, x=17, L[mid] = 17
if x == L[mid]: # x=17=L[mid]이므로 조건만족o
return mid # return 6
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1)
else:
return rec_bin_search(L, x, mid+1, u)
case2. 리스트 L안에 찾으려는 원소x가 존재하지 않는 경우
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31] 이라 하고, 이때의 rec_bin_search(L, 16, 0, 10)을 실행을 시뮬레이션 해보자.
#Step1
def rec_bin_search(L, x, l, u):
if l>u: # l=0, u=10, 0<10이므로 조건만족x
return -1
mid = (l + u) // 2 # mid = (0 + 10)//2 => 5
# l=0, u=10, x=16, L[mid] = 14
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1)
else:
return rec_bin_search(L, x, mid+1, u) # l=(mid+1)=6, u=10, x=16
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31]
#Step2
def rec_bin_search(L, x, l, u):
if l>u: # l=6, u=10, 6<10이므로 조건만족x
return -1
mid = (l + u) // 2 # mid = (6 + 10)//2 => 8
# l=6, u=10, x=16, L[mid] = 24
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1) # l=6, u=(mid-1)=7, x=16
else:
return rec_bin_search(L, x, mid+1, u)
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31]
#Step3
def rec_bin_search(L, x, l, u):
if l>u: # l=6, u=7, 6<7이므로 조건만족x
return -1
mid = (l + u) // 2 # mid = (6 + 7)//2 => 6
# l=6, u=7, x=16, L[mid] = 17
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1) # l=6, u=(mid-1)=5, x=16
else:
return rec_bin_search(L, x, mid+1, u)
L = [1, 3, 7, 9, 13, 14, 17, 21, 24, 27, 31]
#Step4
def rec_bin_search(L, x, l, u):
if l>u: # l=6, u=5, 6>5이므로 조건만족o
return -1 # -1 반환
mid = (l + u) // 2
if x == L[mid]:
return mid
elif x < L[mid]:
return rec_bin_search(L, x, l, mid-1)
else:
return rec_bin_search(L, x, mid+1, u)
'SW 마에스트로 > 코딩 테스트' 카테고리의 다른 글
코딩테스트 준비 - 1 (21.01.31~21.02.06) (0) | 2021.02.01 |
---|---|
코딩테스트 준비 - 0 (21.01.28~21.01.30) (0) | 2021.02.01 |