μ•Œκ³ λ¦¬μ¦˜

이진탐색

alswlfl 2026. 4. 4. 22:19

순차 탐색 vs 이진 탐색

ex) λ¦¬μŠ€νŠΈμ—μ„œ 12인 μ›μ†Œμ˜ μœ„μΉ˜ μ°ΎκΈ°

순차 탐색

리슀트 μ•ˆμ— μžˆλŠ” νŠΉμ •ν•œ 데이터λ₯Ό μ°ΎκΈ° μœ„ν•΄ μ•žμ—μ„œλΆ€ν„° ν•˜λ‚˜μ”© 확인 → μ‹œκ°„λ³΅μž‘λ„: O(N)

μˆœμ°¨νƒμƒ‰ μ˜ˆμ‹œ

이진 탐색

μ •λ ¬λ˜μ–΄ μžˆλŠ” λ¦¬μŠ€νŠΈμ—μ„œ 탐색 λ²”μœ„λ₯Ό μ ˆλ°˜μ”© μ’ν˜€κ°€λ©° 데이터 탐색 → μ‹œκ°„λ³΅μž‘λ„: O(logN)

이진탐색 μ˜ˆμ‹œ

  • 이진탐색 μˆ˜ν–‰ν•  λ•Œ μ‹œμž‘μ (left)와 끝점(end)을 κΈ°μ€€μœΌλ‘œ 탐색 λ²”μœ„ λͺ…μ‹œ
  • 각 λ‹¨κ³„λ§ˆλ‹€ 탐색 λ²”μœ„λ₯Ό 2둜 λ‚˜λˆ„κΈ°
  • 이상적인 경우 λ§€ λ‹¨κ³„λ§ˆλ‹€ λ²”μœ„κ°€ 반으둜 κ°μ†Œ → log λ³΅μž‘λ„λ₯Ό 가짐
  • λŒ€ν‘œμ μΈ 사둀
    • 맀우 넓은(μ–΅ λ‹¨μœ„ 이상) 탐색 λ²”μœ„μ—μ„œ 졜적의 ν•΄λ₯Ό μ°Ύμ•„μ•Ό ν•˜λŠ” 경우
    • 데이터λ₯Ό μ •λ ¬ν•œ 뒀에 λ‹€μˆ˜μ˜ 쿼리(query)λ₯Ό λ‚ λ €μ•Ό ν•˜λŠ” 경우

이진 탐색 μ½”λ“œ

이진 탐색은 배열이 μ •λ ¬λ˜μ–΄μžˆλ‹€λŠ” κ°€μ •ν•˜μ— μˆ˜ν–‰

1. μž¬κ·€ν•¨μˆ˜ 이용

function binarySearch(arr, target, start, end) {
    if (start > end) return -1; // λ²”μœ„ λ„˜μ€ 경우
    let mid = parseInt((start + end) / 2);

    if (arr[mid] === target)
        return mid; // 찾은 경우 쀑간 인덱슀 λ°˜ν™˜
    else if (arr[mid] > target)
        return binarySearch(arr, target, start, mid - 1); // 쀑간 인덱슀 값보닀 target 값이 μž‘μ€ 경우 μ™Όμͺ½ 탐색
    else return binarySearch(arr, target, mid + 1, end); // 쀑간 인덱슀 값보닀 target 값이 더 큰 경우 였λ₯Έμͺ½ 탐색
}

2. 반볡문 이용

function binarySearch(arr, target, start, end) {
    while (start <= end) {
        let mid = parseInt((start + end) / 2);

        if (arr[mid] === target)
            return mid; // 찾은 경우 쀑간 인덱슀 λ°˜ν™˜
        else if (arr[mid] > target)
            end = mid - 1; // 쀑간 인덱슀 값보닀 target 값이 μž‘μ€ 경우 μ™Όμͺ½ 탐색
        else start = mid + 1; // 쀑간 인덱슀 값보닀 target 값이 더 큰 경우 였λ₯Έμͺ½ 탐색
    }
    return -1; // 값을 μ°Ύμ§€ λͺ»ν•œ 경우 -1 리턴
}

 

 

μ •λ ¬λœ λ°°μ—΄μ—μ„œ νŠΉμ • μ›μ†Œ 개수 κ΅¬ν•˜κΈ°

μ½”λ”© ν…ŒμŠ€νŠΈμ—μ„œ μ •λ ¬λœ λ°°μ—΄μ—μ„œ νŠΉμ • λ²”μœ„μ— ν•΄λ‹Ήν•˜λŠ” μ›μ†Œμ˜ 개수λ₯Ό κ³„μ‚°ν•˜λŠ” 문제 μ’…μ’… 쑴재

lowerBound() ν•¨μˆ˜μ™€ upperBound() ν•¨μˆ˜ μ‚¬μš©

lowerBound(arr, x)

μ •λ ¬λœ μˆœμ„œλ₯Ό μœ μ§€ν•˜λ©΄μ„œ λ°°μ—΄ arr에 xλ₯Ό 넣은 κ°€μž₯ μ™Όμͺ½ 인덱슀 λ°˜ν™˜

function lowerBound(arr, target, start, end) {
    while (start < end) {
        const mid = parseInt((start + end) / 2);
        if (arr[mid] >= target)
            end = mid; // μ΅œλŒ€ν•œ μ™Όμͺ½μœΌλ‘œ 이동
        else start = mid + 1;
    }
    return end;
}

upperBound(arr, x)

μ •λ ¬λœ μˆœμ„œλ₯Ό μœ μ§€ν•˜λ©΄μ„œ λ°°μ—΄ arr에 xλ₯Ό 넣은 κ°€μž₯ 였λ₯Έμͺ½ 인덱슀 λ°˜ν™˜

function upperBound(arr, target, start, end) {
    while (start < end) {
        const mid = parseInt((start + end) / 2);
        if (arr[mid] > target) end = mid;
        else start = mid + 1; // μ΅œλŒ€ν•œ 였λ₯Έμͺ½μœΌλ‘œ 이동
    }
    return end;
}

 

countByRange()

μ •λ ¬λœ λ°°μ—΄μ—μ„œ 값이 νŠΉμ • λ²”μœ„μ— μ†ν•˜λŠ” μ›μ†Œμ˜ 개수 계산

function countByRange(arr, leftValue, rightValue) {
    let rightIndex = upperBound(arr, rightValue, 0, arr.length);
    let leftIndex = lowerBound(arr, leftValue, 0, arr.length);
    return rightIndex - leftIndex;
}
// λ°°μ—΄ μ„ μ–Έ
let arr = [1, 2, 3, 3, 3, 3, 4, 4, 8, 9];
// 값이 4인 데이터 개수 좜λ ₯
console.log(countByRange(arr, 4, 4));
// 값이 [-1, 3] λ²”μœ„μ— μžˆλŠ” 데이터 개수 좜λ ₯
console.log(countByRange(arr, -1, 3));

 

 

 

νŒŒνŠΈλ©”νŠΈλ¦­ μ„œμΉ˜

이진 탐색 쑰건: λ³€κ²½ν• (μ΅œμ ν™”ν• ) κ°’ x에 λŒ€ν•΄ f(x)κ°€ 단쑰 증가 ν˜Ήμ€ 단쑰 κ°μ†Œ

- 단쑰 증가 ν•¨μˆ˜: x ≦ y 이면 f(x) ≦ f(y)인 경우 → 계단 ν˜•μ‹ ν˜Ήμ€ μ™Όμͺ½λ³΄λ‹€ 였λ₯Έμͺ½ 값이 더 큼

μ ‘κ·Ό 방법

μ΅œμ ν™” 문제λ₯Ό κ²°μ • 문제(예/μ•„λ‹ˆμ˜€)둜 λ°”κΎΈμ–΄ ν•΄κ²°ν•˜λŠ” 방법

ex) νŠΉμ •ν•œ 쑰건을 λ§Œμ‘±ν•˜λŠ” κ°€μž₯ μ•Œλ§žμ€ 값을 λΉ λ₯΄κ²Œ μ°ΎλŠ” μ΅œμ ν™” 문제

- νŒŒλΌλ©”νŠΈλ¦­ μ„œμΉ˜ λ¬Έμ œλŠ” 이진 탐색 μ΄μš©ν•΄μ„œ ν•΄κ²° κ°€λŠ₯