Skip to content

Commit 3350e50

Browse files
committed
docs: 이분 탐색 알고리즘 문서 업데이트
1 parent f7f25e7 commit 3350e50

File tree

2 files changed

+167
-32
lines changed

2 files changed

+167
-32
lines changed

_posts/2024-02-09-binary-search.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
---
2+
title: 이분 탐색 (Binary Search) 알고리즘
3+
description: 이분 탐색 (Binary Search) 알고리즘에 대해 정리한 페이지입니다.
4+
date: 2024-02-09 00:00:00 +/-TTTT
5+
categories: [Algorithms]
6+
tags: [algorithm]
7+
math: true
8+
toc: true
9+
pin: false
10+
image:
11+
path: /assets/img/algorithms/computer.avif
12+
comments: true
13+
---
14+
15+
<blockquote class="prompt-info"><p><strong><u>Tags</u></strong><br/>
16+
Algorithm</p></blockquote>
17+
18+
## 개요
19+
20+
`이분 탐색(Binary Search)` 알고리즘에 대해 정리한 페이지입니다.
21+
22+
## 이분 탐색 (Binary Search) 알고리즘
23+
24+
### 개념
25+
26+
`이분 탐색` 또는 `이진 탐색` 알고리즘은 정렬된 배열이나 리스트에서 원하는 값을 빠르게 찾는 알고리즘입니다. <b>정렬된 배열이나 리스트</b>를 같은 크기의 두 부분으로 나누고 필요한 부분에서만 탐색하도록 탐색 범위를 <b>절반</b>씩 줄여가며 원하는 값을 빠르게 찾습니다.
27+
28+
### 특징
29+
30+
이분 탐색 알고리즘의 특징은 다음과 같습니다.
31+
32+
- `정렬`
33+
34+
이분 탐색 알고리즘은 <b>정렬된 배열이나 리스트</b>에서만 적용할 수 있습니다.
35+
36+
- `시간 복잡도(Time Complexity)`
37+
38+
선형 탐색과 달리, 중간값을 기준으로 탐색 범위를 절반씩 줄여가며 원하는 값을 찾으므로 `O(log N)`의 시간 복잡도를 갖습니다. 이는 시간 복잡도가 `O(N)`인 선형 탐색보다 빠르므로 정렬된 자료 구조에서 원하는 값을 빠르게 찾을 수 있습니다.
39+
40+
### 구현
41+
42+
다음과 같이 `[2, 3, 5, 7, 11, 13, 17, 21, 23, 29]`이라는 배열이 있을 때, 숫자 25보다 작은 값들 중에서 가장 큰 값을 구하는 문제가 있다고 가정합니다.
43+
44+
```javascript
45+
const arr = [2, 3, 5, 7, 11, 13, 17, 21, 23, 29];
46+
const target = 25;
47+
```
48+
49+
배열 arr이 오름차순으로 정렬되어 있으므로 이분 탐색 알고리즘을 적용할 수 있습니다. 다음과 같이 탐색 구간의 왼쪽 경계, 즉 target보다 작은 값의 인덱스 후보를 나타내는 `left(lower bound)`와 탐색 구간의 오른쪽 경계, 즉 target보다 크거나 같은 값의 첫 위치 후보를 나타내는 `right(upper bound)`를 정의합니다. 이 때 이분 탐색에서 `left``right`의 초깃값은 어떤 값을 찾는가에 따라 신중하게 설정해야 합니다. 이번 문제에서는 arr 내에 target보다 작은 값이 없을 수도 있으므로 left의 초깃값을 -1로 설정하였고, 배열의 모든 값이 target보다 작을 수 있으므로 right의 초깃값을 arr.length로 설정하였습니다.
50+
51+
```javascript
52+
/* ... */
53+
54+
let left = -1;
55+
let right = arr.length;
56+
```
57+
58+
이후 다음과 같이 `left + 1 < right`로 루프 조건을 설정합니다. 이 조건은 `left``right` 사이에 최소 하나의 값만 남아 있을 때까지만 반복하도록 제한합니다.
59+
60+
```javascript
61+
/* ... */
62+
63+
while (left + 1 < right) {
64+
/* ... */
65+
}
66+
```
67+
68+
루프 조건을 설정한 이후 탐색 범위를 절반으로 좁히면서 원하는 값을 찾아냅니다. 다음과 같이 탐색 범위를 절반으로 나누기 위해 `mid` 변수를 선언하고 `[left, right)` 구간의 가운데 인덱스 값을 할당합니다. 그리고 `arr[mid]`의 값이 찾고자 하는 값 후보인지 확인한 후 탐색 범위를 좁힙니다.
69+
70+
```javascript
71+
/* ... */
72+
73+
while (left + 1 < right) {
74+
const mid = Math.floor((left + right) / 2);
75+
76+
if (arr[mid] < target) {
77+
left = mid;
78+
} else {
79+
right = mid;
80+
}
81+
}
82+
```
83+
84+
탐색 이후 찾고자 하는 답이 `left`인지 `right`인지 생각하고 결정합니다. 위의 `arr[mid] < target`이 true인 경우일 때의 mid는 찾고자 하는 답의 후보에 해당하므로 `left`가 찾고자 하는 답임을 확인할 수 있습니다. 따라서 `left`를 선택하여 출력하면 됩니다.
85+
86+
```javascript
87+
/* ... */
88+
89+
if (left >= 0) {
90+
console.log(arr[left]); // 23
91+
} else {
92+
console.log("arr 내에 25보다 작은 값은 없습니다.");
93+
}
94+
```
95+
96+
최종 구현 결과는 다음과 같습니다.
97+
98+
```javascript
99+
const arr = [2, 3, 5, 7, 11, 13, 17, 21, 23, 29];
100+
const target = 25;
101+
let left = -1;
102+
let right = arr.length;
103+
104+
while (left + 1 < right) {
105+
const mid = Math.floor((left + right) / 2);
106+
107+
if (arr[mid] < target) {
108+
left = mid;
109+
} else {
110+
right = mid;
111+
}
112+
}
113+
114+
if (left >= 0) {
115+
console.log(arr[left]); // 23
116+
} else {
117+
console.log("arr 내에 25보다 작은 값은 없습니다.");
118+
}
119+
```
120+
121+
## Example
122+
123+
- <a href="https://www.acmicpc.net/problem/19845" target="_blank">19845번: 넴모넴모 2020</a>
124+
125+
```javascript
126+
const path = process.platform === "linux" ? "/dev/stdin" : "input.txt";
127+
const input = require("fs").readFileSync(path).toString().split("\n");
128+
129+
// N: 게임판의 세로 크기, 1 <= N <= 250_000
130+
// Q: 레이저를 설치할 수 있는 위치의 수, 1 <= Q <= 250_000
131+
const [N, Q] = input[0].split(" ").map(Number);
132+
const arr = input[1].split(" ").map(Number); // 1 <= arr[i] <= 10^9
133+
let answer = "";
134+
135+
for (let i = 2; i < 2 + Q; i++) {
136+
const [col, row] = input[i].split(" ").map(Number);
137+
138+
let left = 0;
139+
let right = N;
140+
141+
while (left + 1 < right) {
142+
const mid = Math.floor((left + right) / 2);
143+
144+
if (arr[mid] < col) {
145+
right = mid;
146+
} else {
147+
left = mid;
148+
}
149+
}
150+
151+
let result = arr[row - 1] - col;
152+
result += right - row + 1;
153+
154+
if (result < 0) {
155+
result = 0;
156+
}
157+
158+
answer += `${result}\n`;
159+
}
160+
161+
console.log(answer.trim());
162+
```
163+
164+
## 참고 자료
165+
166+
- <a href="https://namu.wiki/w/이진%20탐색?from=이분%20탐색" target="_blank">이진 탐색 - 나무위키</a>
167+
- <a href="https://www.acmicpc.net/blog/view/109" target="_blank">이분 탐색(Binary Search) 헷갈리지 않게 구현하기</a>

_posts/2024-02-09-bisection-method.md

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)