CS/알고리즘_개념

이진탐색(Binary Search), 순차탐색(Sequential Search) + Parametric Search

Jedy_Kim 2021. 5. 19. 15:12
728x90

*이진탐색(Binary Search)

분할정복과 이진탐색

    • 분할정복 알고리즘(Divide and Conquer)
      • 문제를 하나 또는 둘 이상으로 나눈다. (Divide)
      • 나눠진 문제가 충분히 작고, 해결이 가능하다면 해결하고, 그렇지 않다면 다시 나눈다.(conquer)
    • 이진탐색
      • 리스트를 두 개의 서브리스트로 나눈다. (Divide)
      • (1) 검색할 숫자(search) > 중간 값 => 뒷 부분의 서브리스트에서 검색할 숫자를 찾는다.
      • (2) 검색할 숫자(search) < 중간 값 => 앞 부분의 서브리스트에서 검색할 숫자를 찾는다.

#코드1 : 재귀호출 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import random
 
def binary_search(data, search):
  if len(data) == 1 and search == data[0]:
    return True
  if len(data) == 1 and search != data[0]:
    return False
  if len(data) == 0:
    return False
  
  medium = len(data)//2 # 나누기 연산 후 소수점 이하의 수를 버리고 정수부분만 구함
  if search == data[medium]:
    return True
  else:
    if search > data[medium]:
      return binary_search(data[medium+1:], search)
    else:
      return binary_search(data[:medium], search)
 
  
 
data_list = random.sample(range(100), 10)
data_list.sort()
print(data_list)
getRes = binary_search(data_list, 66)
if getRes == True:
  print('YES')
else
  print('NO')
cs

#코드2 : 재귀호출 사용안함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def binary_search2(data, search):
    testCnt = 0
    while True:
        if len(data) == 1 and search == data[0]:
            return True
        if len(data) == 1 and search != data[0]:
            return False
        if len(data) == 0:
            return False
        
        medium = len(data)//2 # 나누기 연산 후 소수점 이하의 수를 버리고 정수부분만 구함
        if search == data[medium]:
            return True
        else:
            if search > data[medium]:
                data = data[medium+1:]
            else:
                data = data[:medium]
 
  
 
data_list = [8182441643184515466]
 
getRes = binary_search2(data_list, 66)
if getRes == True:
  print('YES')
else
  print('NO')
cs

 

#시간복잡도 : O(logn)

*순차탐색(Sequential Search)

  • 데이터가 담겨있는 리스트를 앞에서부터 하나씩 비교해서 원하는 데이터를 찾는 방법.

#코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import random
 
def sequential_search(data, search):
  for i in range(len(data_list)):
    if data_list[i] == search:
      return True
  return False
 
 
data_list = random.sample(range(100), 10)
getRes = sequential_search(data_list, 66)
print(data_list)
if getRes == True:
  print('YES')
else:
  print('NO')
cs

#시간복잡도 : O(n)

*파라메트릭 서치(Parametric Search)

 

[이분탐색] 파라메트릭 서치(Parametric Search)

이분탐색 알고리즘의 개념을 학습하고 나면 한가지 궁금증이 생긴다. 이분탐색 알고리즘이 어떤식으로 문제에 출제될 수 있을까? 순차 탐색보다 더 빠르게 데이터를 탐색할 수 있어서 사용되는

velog.io

#코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
n, s = map(int, input().split())
getInfo = list(map(int, input().split()))
 
# 구간 : 1 2 3 4 5 6 7 8 9 10 11 12...
#        x x x o o o o o o o o o o 
#        s(초기값 : 1)......................e(초기값 : n)
 
start = 1 # start는 무조건 X를 가리킴
end = n   # end는 무조건 O를 가리킴
 
 
def check(interval):
  # 구간의 길이 interval만큼 정했을 때, 
  # 그 합이 S이상인 경우가 있는가?
  # 있으면 True, 아니면 False
  # 2 1 8 1 3 7 2 6 3
  # - - -
  #   - - -
  # 2 1 8 에서 다음으로 넘어가려면 
  # 0번째 2를 빼주고, 3번째 1을 더해준다
  sum = 0
  # 1. 앞 세개의 합
  for i in range(interval):
    sum += getInfo[i]
  if sum >= s: 
    return True
  # 2. 다음으로 이동
  for i in range(n-interval):
    sum = sum - getInfo[i] + getInfo[i+interval]
    if sum >= s: return True
  return False
  
  
if check(1): print(1#구간 1이 될 경우... 1출력
if check(n) == Falseprint('-1'#구간 마지막이 안될 경우 -1출력
 
while start + 1 < end: # start와 end가 붙으면 끝
  mid = (start + end) // 2
  if check(mid): end = mid
  else: start = mid
  
print(end)
    
cs

**입력 

9 14
2 1 8 1 3 7 2 6 3

** 출력

3

 

#코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import sys
 
def check(interval):
  global getInfo
  # 구간의 길이 interval만큼 정했을 때, 그 합이 S이상인 경우가 있는가?
  # 있으면 True, 없으면 False
  # 9 14
  # 2 1 8 1 3 7  2 6 3
  
  # 1. 앞의 세 개(구간의 길이 만큼 즉 interval)의 숫자를 더해준다.
  sum = 0
  for i in range(interval): 
    sum += getInfo[i]
  if sum >= s: return True # 앞의 구간의 합이 이미 s를 넘어버린 경우
  
  # 2. 1 8 1 부터 시작해서 구간을 돌아야한다. 6번 돌 수 있다.
  #    9 - 3 = 6 -> n - interval 
  for i in range(n-interval):
    # ..2 1 8 1 ..구간에서 1 8 1 의 합은
    # 맨 앞구간의 합(sum)에서 앞의 2를 빼고 뒤의 1을 더해준 것과 같다.
    sum = sum - getInfo[i] + getInfo[i+interval] 
    if sum >= s: return True
  
  return False
  
 
if __name__ == "__main__":
  n, s    = map(int, input().split())
  getInfo = list(map(int, input().split()))
  
  # 구간
  # 1 2 3 4 5 6 7 8 9 10 11 12, ..
  # s                       e
  start = 1 # start는 무조건 X를 가리킴
  end   = n # end는 무조건 O를 가리킴
  flag  = True 
  
  if check(1): # 구간 1이 가능하다면 1이 답.
    print(1)
    flag = False
  
  if not check(n): # 구간 n을 해봤을 경우에 안된다면 가능한 방법이 없다.
    print(-1)
    flag = False
  
  
  if flag:
    # 1 2 3 4 5 ... 10 11 12 ...
    # x x x x x ... x  O  O ...
    #               s  e    => start+1 == end 끝났다는 의미
    while start+1 < end:
      mid = (start+end)//2 
      if check(mid): # mid의 값이 O라는 뜻 즉 end가 움직여야된다.
        end = mid
      else:
        start = mid
    print(end)
 
    # 2 1 8 1 3 7 2 6 3
    # s               e
    # 9 - 1 = 8
cs

 

반응형