Algorithm&Data structure/JS alg.
이진탐색(Binary Search)
bright jazz music
2024. 11. 1. 17:19
이진탐색은 데이터를 반으로 나눠가면서 데이터를 찾는 방식을 뜻한다.
이진탐색은 특성상 데이터가 정렬된 상태여야 한다. 데이터가 정렬된 상태라면 아래의 순서로 진행한다.
1단계: 전체 배열의 중간 인덱스의 원소와 검색값을 비교한다.
2단계: 검색값이 배열의 좌우 중 한 곳에 포함되면 다시 1단계를 반복한다.
즉, 중간을 자르고 크기를 비교하는 것을 반복하는 것이 이진탐색 알고리즘이며, 선형탐색보다 검색 횟수가 적기 때문에 시간 복잡도에서 우위가 있다.
// 중앙 값을 구해서 나머지를 버린다.(이 때문에 mid가 left값과 더 가까울 수 있음)
// 배열에서 mid인덱스 값이 타겟값인 경우 리턴한다.
// mid인덱스 값이 타겟보다 작으면 mid에 1을 더한 값을 left에 할당한다. 새로 만들 mid값을 오른쪽으로 당기기 위해서다.
// 큰 경우 mid -1 한 값을 right에 할당한다. 새로 만들 mid값을 왼쪽으로 당기기 위해서다.
// 위 과정을 반복하면 하나의 값에 수렴하게 되고, 이것이 mid, 즉 target값이 되면서 반환된다.
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while( left <= right) {
let mid = Math.floor((left + right) / 2);
if(arr[mid] === target) {
return mid;
} else if(arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
console.log(binarySearch([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 7));
// 6 (배열의 6번째 인덱스)
이진탐색은 O(log n)의 시간 복잡도를 가진다. 중간값을 취하는 방식은 탐색 시간을 로그 선형적으로 감소시킨다. 이진 탐색을 자바스크립트로 구현할 때 재귀적 형태를 만들어 코드를 구현하기도 한다. 그러면 추가적인 공간 복잡도를 발생시키므로 O(n)의 공간 복잡도를 만들 수 있다. 위와 같이 추가 메모리를 차지하지 않는 형태로 작성해야 O(1)의 공간 복잡도를 가질 수 있다.
예제1)
/*
서점으 ㅣ모든 책이 부된 ISBN 번호대로 정렬돼 있다고 가정.
책을 찾는 함수를 작성하시오.
*/
let bookISBNs = [9788998139019, 9788998139020, 9788998139021, 9788998139023];
const binarySearch = (arr, target) => {
let left = 0;
let right = arr.length - 1;
while(left <= right) {
let mid = Math.floor((left + right) / 2);
if(arr[mid] === target) {
return mid;
} else if(arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
console.log(binarySearch(bookISBNs, 9788998139020));
// 1
console.log(binarySearch(bookISBNs, 9788998139021));
// 2
console.log(binarySearch(bookISBNs, 9788998139023));
// 3
예제2)
/*
향기로운 학교 만들기
복도에는 여러 교실이 있고 교실의 간격은 다르다.
배치할 수 있는 꽃나무도 여러 개 있다.
인접한 꽃나무끼리의 거리를 최대한 멀리하여 여러 교실에 향이 닿게 하고자 한다.
- 복도는 x축이라고 보고 교실의 위치는 x좌표 위에 있는 점으로 가정한다.
- 출력값은 꽃나무를 배치할 위치를 배열로 반환한다.
*/
let CLASSROOMS = [4, 7, 2, 5, 10, 13];
let FLOWER_TREES = 3;
// 이진탐색 전 정렬
CLASSROOMS.sort((a,b) => a - b);
let start = CLASSROOMS[0];
let end = CLASSROOMS[CLASSROOMS.length - 1];
let result = 0;
while (start <= end) {
let mid = Math.floor(( start + end ) / 2);
let value = CLASSROOMS[0]
let count = 1;
for(let i = 1; i < CLASSROOMS.length; i++) {
if(CLASSROOMS[i] - value >= mid) {
value = CLASSROOMS[i];
count++
}
}
if(count >= FLOWER_TREES) {
result = mid;
start = mid + 1;
} else {
end = mid - 1;
}
}
let treePositions = [CLASSROOMS[0]];
let lastPosition = CLASSROOMS[0];
for(let i = 1; i < CLASSROOMS.length; i++) {
if( CLASSROOMS[i] - lastPosition >= result) {
treePositions.push(CLASSROOMS[i]);
lastPosition = CLASSROOMS[i];
}
}
console.log(treePositions);
// [ 2, 7, 13 ]