contents

πŸ”Ž μ½”λ”© ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ 탐색 μ•Œκ³ λ¦¬μ¦˜ κ°€μ΄λ“œ

μ½”λ”© ν…ŒμŠ€νŠΈμ™€ 기술 λ©΄μ ‘μ—μ„œ 자주 λ“±μž₯ν•˜λŠ” 탐색 μ•Œκ³ λ¦¬μ¦˜μ„ μžμ„Ένžˆ μ •λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€. 각 μ•Œκ³ λ¦¬μ¦˜μ˜ 핡심 κ°œλ…, μ‚¬μš© 사둀, μ‹œκ°„ λ³΅μž‘λ„, Java 예제 μ½”λ“œλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

1. πŸ“Œ μ„ ν˜• 탐색 (Linear Search)

🧠 κ°œμš”:
λ°°μ—΄μ˜ 첫 번째 μš”μ†ŒλΆ€ν„° 순차적으둜 νƒμƒ‰ν•˜λ©° μ›ν•˜λŠ” 값을 μ°ΎμŠ΅λ‹ˆλ‹€.

⏱ μ‹œκ°„ λ³΅μž‘λ„: O(n)
🧩 μ‚¬μš© 예: μ •λ ¬λ˜μ§€ μ•Šμ€ μž‘μ€ λ°°μ—΄

int linearSearch(int[] arr, int target) {
    for (int i = 0; i < arr.length; i++)
        if (arr[i] == target) return i;
    return -1;
}

2. πŸ“Œ 이진 탐색 (Binary Search)

🧠 κ°œμš”:
μ •λ ¬λœ 배열에 λŒ€ν•΄, κ°€μš΄λ° 값을 κΈ°μ€€μœΌλ‘œ 탐색 λ²”μœ„λ₯Ό 반으둜 쀄이며 κ²€μƒ‰ν•©λ‹ˆλ‹€.

⏱ μ‹œκ°„ λ³΅μž‘λ„: O(log n)
🧩 μ‚¬μš© 예: μ •λ ¬λœ λ°°μ—΄μ˜ κ°’ 검색

int binarySearch(int[] arr, int target) {
    int left = 0, right = arr.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) return mid;
        if (arr[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

βœ… μ‘μš©:

3. πŸ“Œ μ‚ΌλΆ„ 탐색 (Ternary Search)

🧠 κ°œμš”:
데이터가 "λŠ˜μ—ˆλ‹€ μž‘μ•„μ§€λŠ”" (unimodal) 곑선(ν•¨μˆ˜)일 λ•Œ, μ΅œλŒ€/μ΅œμ†Œκ°’μ„ λΉ λ₯΄κ²Œ μ°ΎκΈ° μœ„ν•œ 둜그 κΈ‰ 탐색

⏱ μ‹œκ°„ λ³΅μž‘λ„: O(log n)
🧩 μ‚¬μš© 예: μ΅œλŒ€κ°’ μœ„μΉ˜ μ°ΎκΈ° (ex: 이진 탐색 λŒ€μ‹  μ“Έ 수 있음)

double ternarySearch(double left, double right, Function<Double, Double> f) {
    double eps = 1e-9;
    while (right - left > eps) {
        double m1 = left + (right - left) / 3;
        double m2 = right - (right - left) / 3;
        if (f.apply(m1) < f.apply(m2)) left = m1;
        else right = m2;
    }
    return (left + right) / 2;
}

4. πŸ“Œ 점프 탐색 (Jump Search)

🧠 κ°œμš”:
μ •λ ¬λœ λ°°μ—΄μ—μ„œ 일정 간격(√n)만큼 κ±΄λ„ˆλ›°λ©° 탐색. λ²”μœ„ 내에 λ“€μ–΄κ°„ λ’€ μ„ ν˜• 탐색을 μˆ˜ν–‰.

⏱ μ‹œκ°„ λ³΅μž‘λ„: O(√n)
🧩 μ‚¬μš© 예: μ •λ ¬λœ 쀑간 크기 리슀트

int jumpSearch(int[] arr, int x) {
    int n = arr.length, step = (int)Math.floor(Math.sqrt(n));
    int prev = 0;
    while (arr[Math.min(step, n) - 1] < x) {
        prev = step;
        step += (int)Math.floor(Math.sqrt(n));
        if (prev >= n) return -1;
    }
    for (int i = prev; i < Math.min(step, n); i++)
        if (arr[i] == x) return i;
    return -1;
}

5. πŸ“Œ μ§€μˆ˜ 탐색 (Exponential Search)

🧠 κ°œμš”:
λ¨Όμ € 1, 2, 4, 8 μ‹μœΌλ‘œ λ²”μœ„λ₯Ό λ„“νžˆλ©° μ μ ˆν•œ ꡬ간을 μ°Ύκ³ , κ·Έ μ•ˆμ—μ„œ 이진 탐색 μˆ˜ν–‰.

⏱ μ‹œκ°„ λ³΅μž‘λ„: O(log n)

int exponentialSearch(int[] arr, int x) {
    int n = arr.length, bound = 1;
    while (bound < n && arr[bound] < x) bound *= 2;
    int left = bound / 2, right = Math.min(bound, n - 1);
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == x) return mid;
        if (arr[mid] < x) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

6. πŸ“Œ 보간 탐색 (Interpolation Search)

🧠 κ°œμš”:
μ •λ ¬λœ 값이 κ· λ“±ν•˜κ²Œ λΆ„ν¬λ˜μ–΄ μžˆμŒμ„ κ°€μ •ν•˜κ³ , 이진 탐색보닀 더 μ •κ΅ν•˜κ²Œ μœ„μΉ˜λ₯Ό μΆ”μΈ‘.

⏱ μ‹œκ°„ λ³΅μž‘λ„: 평균 O(log log n), μ΅œμ•… O(n)
🧩 단점: 배열이 κ· μΌν•˜μ§€ μ•ŠμœΌλ©΄ λΉ„νš¨μœ¨μ 

int interpolationSearch(int arr[], int x) {
    int lo = 0, hi = arr.length - 1;
    while (lo <= hi && x >= arr[lo] && x <= arr[hi]) {
        int pos = lo + ((hi-lo)*(x-arr[lo])) / (arr[hi]-arr[lo]);
        if (arr[pos] == x) return pos;
        if (arr[pos] < x) lo = pos + 1;
        else hi = pos - 1;
    }
    return -1;
}

7. πŸ“Œ ν”Όλ³΄λ‚˜μΉ˜ 탐색 (Fibonacci Search)

🧠 κ°œμš”:
ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄μ„ 기반으둜 μ™Όμͺ½/였λ₯Έμͺ½ λ²”μœ„ λΆ„ν• . 이진 νƒμƒ‰μ˜ λŒ€μ•ˆ

⏱ μ‹œκ°„ λ³΅μž‘λ„: O(log n)

int fibonacciSearch(int arr[], int x) {
    int n = arr.length;
    int fibMm2 = 0, fibMm1 = 1, fibM = fibMm1 + fibMm2;
    while (fibM < n) {
        fibMm2 = fibMm1;
        fibMm1 = fibM;
        fibM = fibMm1 + fibMm2;
    }
    int offset = -1;
    while (fibM > 1) {
        int i = Math.min(offset + fibMm2, n - 1);
        if (arr[i] < x) {
            fibM = fibMm1;
            fibMm1 = fibMm2;
            fibMm2 = fibM - fibMm1;
            offset = i;
        } else if (arr[i] > x) {
            fibM = fibMm2;
            fibMm1 -= fibMm2;
            fibMm2 = fibM - fibMm1;
        } else return i;
    }
    if (fibMm1 == 1 && arr[offset + 1] == x) return offset + 1;
    return -1;
}

8. πŸ“Œ 자료ꡬ쑰 기반 탐색

πŸ”Έ ν•΄μ‹œ 탐색 (Hash Table)

HashSet<Integer> set = new HashSet<>();
set.add(10);
boolean found = set.contains(10); // true

πŸ”Έ 이진 탐색 트리 (BST), κ· ν˜• 이진 트리

TreeSet<Integer> bst = new TreeSet<>();
bst.add(20); bst.add(5);
Integer next = bst.higher(10); // 20

9. πŸ“Œ κ·Έλž˜ν”„/트리 탐색 – DFS & BFS

πŸ”Ή DFS (깊이 μš°μ„  탐색)

void dfs(int node, boolean[] visited, List<Integer>[] adj) {
    visited[node] = true;
    for (int next : adj[node])
        if (!visited[next]) dfs(next, visited, adj);
}

πŸ”Ή BFS (λ„ˆλΉ„ μš°μ„  탐색)

void bfs(int start, boolean[] visited, List<Integer>[] adj) {
    Queue<Integer> queue = new LinkedList<>();
    queue.add(start);
    visited[start] = true;
    while (!queue.isEmpty()) {
        int node = queue.poll();
        for (int next : adj[node]) {
            if (!visited[next]) {
                queue.add(next);
                visited[next] = true;
            }
        }
    }
}

10. πŸ’‘ 싀무/ν…ŒμŠ€νŠΈ 팁

βœ… μš”μ•½ ν‘œ

μ•Œκ³ λ¦¬μ¦˜ 자료ꡬ쑰/쑰건 μ‹œκ°„ λ³΅μž‘λ„ ν™œμš© 상황
μ„ ν˜• 탐색 일반 λ°°μ—΄ O(n) μ •λ ¬ μ•ˆ 된 데이터
이진 탐색 μ •λ ¬λœ λ°°μ—΄ O(log n) 이뢄 검색, Lower/Upper Bound λ“±
ν•΄μ‹œ 탐색 HashSet/Map O(1) (평균) λΉ λ₯Έ 쑴재 검사, 쀑볡 제거
BST 탐색 TreeSet/TreeMap O(log n) μ •λ ¬ 기반 λ²”μœ„ 검색, floor/ceil
DFS/BFS κ·Έλž˜ν”„/트리 O(N+E) μ—°κ²°μ„± 확인, 경둜 탐색, μƒνƒœ κ³΅κ°„μ—μ„œ 탐색

references