๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โญ Personal_Study/CS

CS ๋ฉด์ ‘ ์งˆ๋ฌธ ์ •๋ฆฌ - ์•Œ๊ณ ๋ฆฌ์ฆ˜

by ํฌ์ŠคํŠธ์‰์ดํฌ 2023. 2. 19.

์•Œ๊ณ ๋ฆฌ์ฆ˜

1. ์‹œ๊ฐ„ ๋ณต์žก๋„

์‹œ๊ฐ„ ๋ณต์žก๋„(Time Compexity)

  • ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋žจ์˜ ์ž…๋ ฅ๊ฐ’๊ณผ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ์‹œ๊ฐ„์˜ ์ƒ๊ด€๊ด€๊ณ„
  • ํšจ์œจ์  ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ž€?
    • ์ž…๋ ฅ๊ฐ’์ด ์ปค์ง์— ๋”ฐ๋ผ ์ฆ๊ฐ€ํ•˜๋Š” ์‹œ๊ฐ„์˜ ๋น„์œจ์„ ์ตœ์†Œํ™”ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜

์‹œ๊ฐ„ ๋ณต์žก๋„์˜ ์ข…๋ฅ˜

O(1): ์ƒ์ˆ˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

โœ” ex: ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•œ ์ ‘๊ทผ

์˜ˆ์‹œ ์ฝ”๋“œ
int[] arr = {1, 2, 3, 4, 5};
int x = arr[2]; // retrieves the element at index 2

O(N): ์„ ํ˜• ์‹œ๊ฐ„ ๋ณต์žก๋„

โœ” ex: ์ผ๋ฐ˜์ ์ธ ์ˆœํšŒ ๋ฐ ํƒ์ƒ‰

์˜ˆ์‹œ ์ฝ”๋“œ
int[] arr = {5, 3, 8, 1, 7, 2};

int max = Integer.MIN_VALUE;

for (int i = 0; i < arr.length; i++) {
    if (arr[i] > max) {
        max = arr[i];
    }
}

System.out.println("Maximum value: " + max);

O(logN): ๋กœ๊ทธ ์‹œ๊ฐ„ ๋ณต์žก๋„

โœ” ex: ์ด๋ถ„ํƒ์ƒ‰

์˜ˆ์‹œ ์ฝ”๋“œ
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int target = 5;

int left = 0;
int right = arr.length - 1;

while (left <= right) {
    int mid = (left + right) / 2;
    if (arr[mid] == target) {
        System.out.println("Found at index " + mid);
        break;
    } else if (arr[mid] < target) {
        left = mid + 1;
    } else {
        right = mid - 1;
    }
}

O(NlogN): ์„ ํ˜• ๋กœ๊ทธ ์‹œ๊ฐ„ ๋ณต์žก๋„

โœ” ex: ์ •๋ ฌ (ํ€ต ์†ŒํŠธ, ๋จธ์ง€ ์†ŒํŠธ ๋“ฑ)

์˜ˆ์‹œ ์ฝ”๋“œ
void quicksort(int[] arr, int left, int right) {
    if (left < right) {
        int pivotIndex = partition(arr, left, right);
        quicksort(arr, left, pivotIndex - 1);
        quicksort(arr, pivotIndex + 1, right);
    }
}

int partition(int[] arr, int left, int right) {
    int pivotValue = arr[right];
    int i = left - 1;

    for (int j = left; j < right; j++) {
        if (arr[j] < pivotValue) {
            i++;
            swap(arr, i, j);
        }
    }

    swap(arr, i + 1, right);

    return i + 1;
}

void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

int[] arr = {5, 3, 8, 1, 7, 2};
quicksort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));

O(N^2)

โœ” ex: ๋ฒ„๋ธ” ์†ŒํŠธ, ์ด์ฐจ์› ๋ฐฐ์—ด ํƒ์ƒ‰ ๋“ฑ๋“ฑ

์˜ˆ์‹œ ์ฝ”๋“œ
public static void bubbleSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        boolean swapped = false;
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
                swapped = true;
            }
        }
        if (!swapped) {
            break;
        }
    }
}

O(2^N): ์ง€์ˆ˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

โœ” ex: ๋ถ€๋ถ„์ง‘ํ•ฉ ๊ตฌํ•˜๊ธฐ

์˜ˆ์‹œ ์ฝ”๋“œ
void generateSubsets(int[] arr) {
    int n = arr.length;
    int totalSubsets = (int) Math.pow(2, n);
    for (int i = 0; i < totalSubsets; i++) {
        for (int j = 0; j < n; j++) {
            if ((i & (1 << j)) != 0) {
                System.out.print(arr[j] + " ");
            }
        }
        System.out.println();
    }
}

int[] arr = {1, 2, 3};
generateSubsets(arr);

2. ์ •๋ ฌ

โœ” ์‹ค์ œ cs ์งˆ๋ฌธ์—๋Š” ๊ฐ ์ •๋ ฌ ๋ฐฉ์‹์˜ ๊ฐœ๋…์— ๋Œ€ํ•œ ๋น„๊ต์™€ ์ˆ˜๋„ ์ฝ”๋“œ ์ž‘์„ฑ์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ž˜ ์•Œ์•„๋‘์ž!

๋ฒ„๋ธ” ์ •๋ ฌ (Bubble Sort)

โœ” ์ธ์ ‘ํ•œ ๋‘ ์›์†Œ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ •๋ ฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๊ณ  ์ง๊ด€์ ์ด์ง€๋งŒ ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(N^2)

์˜ˆ์‹œ ์ฝ”๋“œ
public static void bubbleSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

์„ ํƒ ์ •๋ ฌ (Selection Sort)

โœ” ์ฃผ์–ด์ง„ ๋ฐฐ์—ด์—์„œ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์„ ์ฐพ์•„์„œ ์•ž์œผ๋กœ ๊ฐ€์ง€๊ณ  ์˜ค๋Š” ๊ฒƒ์„ ๋ฐ˜๋ณตํ•˜์—ฌ ์ •๋ ฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ์‹œ๊ฐ„ ๋ณต์žก๋„: O(N^2)

์˜ˆ์‹œ ์ฝ”๋“œ
public static void selectionSort(int[] arr) {
    int n = arr.length;

    for (int i = 0; i < n - 1; i++) {
        int minIndex = i;

        // ์ฃผ์–ด์ง„ ๋ฐฐ์—ด์—์„œ ์ตœ์†Ÿ๊ฐ’ ์ฐพ๊ธฐ
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }

        // ์ตœ์†Ÿ๊ฐ’๊ณผ ์œ„์น˜ ๋ฐ”๊ฟ”์ฃผ๊ธฐ
        int temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
}

์‚ฝ์ž… ์ •๋ ฌ (Insertion Sort)

โœ” ๋ฐฐ์—ด์˜ ๋ชจ๋“  ์š”์†Œ๋ฅผ ์•ž์— ์›์†Œ๋“ค๊ณผ ๋น„๊ต ํ•˜์—ฌ, ์ž์‹ ์˜ ์œ„์น˜๋ฅผ ์ฐพ์•„ ์‚ฝ์ž…ํ•จ์œผ๋กœ์จ ์ •๋ ฌ์„ ์™„์„ฑํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ์‹œ๊ฐ„ ๋ณต์žก๋„: O(N^2)

์˜ˆ์‹œ ์ฝ”๋“œ
public static void insertionSort(int[] arr) {
    int n = arr.length;

    for (int i = 1; i < n; i++) {
        int key = target[i];
        int j = i - 1;

        // ํƒ€๊ฒŸ์ด ์ด์ „ ์›์†Œ๋ณด๋‹ค ์ž‘์œผ๋ฉด ์ด์ „ ์›์†Œ๋ฅผ ๋’ค๋กœ ํ•œ ์นธ์”ฉ ๋ฏผ๋‹ค
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }

        // ํƒ€๊ฒŸ์„ ์œ„์น˜์— ๋งž๊ฒŒ ์‚ฝ์ž…ํ•ด์ค€๋‹ค
        arr[j + 1] = target;
    }
}

ํ€ต ์ •๋ ฌ (Quick Sort)

โœ” ํŠน์ •ํ•œ ๊ฐ’(ํ”ผ๋ฒ—)์„ ๊ธฐ์ค€์œผ๋กœ ํฐ ์ˆซ์ž์™€ ์ž‘์€ ์ˆซ์ž๋ฅผ ์„œ๋กœ ๊ตํ™˜ํ•œ ๋’ค์— ๋ฐฐ์—ด์„ ๋ฐ˜์œผ๋กœ ๋ถ„ํ• ํ•˜์—ฌ ์ •๋ ฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ๋ถ„ํ•  ์ •๋ณต

โœ” ๋ถˆ์•ˆ์ • ์ •๋ ฌ

โœ” O(nlogn) / O(N^2) (์ตœ์•…)

โœ” ์ตœ์•…์ธ ๊ฒฝ์šฐ: ์ด๋ฏธ ์ •๋ ฌ๋˜์–ด์žˆ๋Š” ๋ฐฐ์—ด, ํ”ผ๋ฒ—์ด ์ตœ๋Œ“๊ฐ’์ด๋‚˜ ์ตœ์†Ÿ๊ฐ’์ผ ๋•Œ

  • [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    → 1์„ ํ”ผ๋ฒ—์œผ๋กœ ์žก๊ณ  ์ง„ํ–‰ํ•˜๋ฉด ๋ชจ๋“  ์ˆ˜๋งˆ๋‹ค ํ”ผ๋ฒ—์„ ์žก๊ณ  ํƒ์ƒ‰์„ ํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ O(n^2)๊ฐ€ ๋œ๋‹ค!
์˜ˆ์‹œ ์ฝ”๋“œ
// ๋ถ„ํ•  ์ •๋ณต ํ€ต ์ •๋ ฌ
public static void quickSort(int[] arr, int low, int high) {
    if (low < high) {
        int pivotIndex = partition(arr, low, high);
        quickSort(arr, low, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, high);
    }
}


// ํ”ผ๋ฒ— ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
private static int partition(int[] arr, int low, int high) {

    // ์ค‘์•™ ํ”ผ๋ฒ— 
    int mid = low + (high - low) / 2;
    int pivot = arr[mid];
    int i = low - 1;
    int j = high + 1;

    while (true) {

        // ํ”ผ๋ฒ—๋ณด๋‹ค ์ž‘์€ ๊ฐ’
        do {
            i++;
        } while (arr[i] < pivot); 

        // ํ”ผ๋ฒ— ๋ณด๋‹ค ํฐ ๊ฐ’
        do {
            j--;
        } while (arr[j] > pivot);

        if (i >= j) {
            // ์—‡๊ฐˆ๋ฆฐ ๊ฒฝ์šฐ ํ”ผ๋ฒ— ๊ต์ฒด ํ›„ ๋ฐ˜ํ™˜
            return j;
        }

        // ํ”ผ๋ฒ— ์™ผ์ชฝ์—๋Š” ์ž‘์€ ๊ฐ’์ด, ์˜ค๋ฅธ์ชฝ์—๋Š” ํฐ ๊ฐ’์ด ์œ„์น˜ํ•˜๊ฒŒ ๋œ๋‹ค
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

๋ณ‘ํ•ฉ ์ •๋ ฌ (Merge Sort)


์ถœ์ฒ˜: ํŒŒ์ด์ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ธํ„ฐ๋ทฐ

โœ” ์›์†Œ ๊ฐœ์ˆ˜๊ฐ€ 0์ด๋‚˜ 1์ด ๋  ๋•Œ๊นŒ์ง€ ๊ฐ’์„ ์ชผ๊ฐ  ๋’ค ๋ณ‘ํ•ฉํ•˜๋ฉด์„œ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ๋ฒ•

โœ” ์‹œ๊ฐ„๋ณต์žก๋„: O(logN)

โœ” ์•ˆ์ • ์ •๋ ฌ

โœ” ์ž„์‹œ ๋ฐฐ์—ด์„ ์œ„ํ•œ ์ถ”๊ฐ€ ๊ณต๊ฐ„ ๋ณต์žก๋„

์˜ˆ์‹œ ์ฝ”๋“œ
// ๋ถ„ํ•  ์ •๋ณต์œผ๋กœ ๋ณ‘ํ•ฉ์ •๋ ฌ ์ˆ˜ํ–‰
public static void mergeSort(int[] arr, int low, int high) {
    if (low < high) {
        int mid = low + (high - low) / 2;
        mergeSort(arr, low, mid);
        mergeSort(arr, mid + 1, high);
        merge(arr, low, mid, high);
    }
}

private static void merge(int[] arr, int low, int mid, int high) {

    // ๋ฐฐ์—ด ๋ถ„ํ• 
    int n1 = mid - low + 1;
    int n2 = high - mid;

    int[] leftArr = new int[n1];
    int[] rightArr = new int[n2];

    for (int i = 0; i < n1; i++) {
        leftArr[i] = arr[low + i];
    }

    for (int j = 0; j < n2; j++) {
        rightArr[j] = arr[mid + j + 1];
    }

    int i = 0;
    int j = 0;
    int k = low;

    // ๋ถ„ํ• ํ•œ ๋ฐฐ์—ด ์ •๋ ฌ
    while (i < n1 && j < n2) {
        if (leftArr[i] <= rightArr[j]) {
            arr[k] = leftArr[i];
            i++;
        } else {
            arr[k] = rightArr[j];
            j++;
        }
        k++;
    }

    while (i < n1) {
        arr[k] = leftArr[i];
        i++;
        k++;
    }

    while (j < n2) {
        arr[k] = rightArr[j];
        j++;
        k++;
    }
}

๊ฐ ์ •๋ ฌ์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„

3. ์žฌ๊ท€

โœ” ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ํ•จ์ˆ˜๊ฐ€ ์ž๊ธฐ ์ž์‹ ์„ ๋˜ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ๋ฐ˜ํ™˜ / ์ค‘๋‹จ ์กฐ๊ฑด์„ ์ž˜ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค!

์˜ˆ์‹œ ์ฝ”๋“œ (ํŒฉํ† ๋ฆฌ์–ผ / ํ”ผ๋ณด๋‚˜์น˜)
// ํŒฉํ† ๋ฆฌ์–ผ
public static int factorial(int n) {
    if (n == 0) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}
// ํ”ผ๋ณด๋‚˜์น˜
public static int fibonacci(int n) {
    if (n <= 1) {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

4. Dynamic Programming

โœ” ์ž‘์€ ๋ถ€๋ถ„ ๋ฌธ์ œ๋“ค์˜ ํ•ด๋ฅผ ๊ตฌํ•˜๊ณ  ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณด๋‹ค ํฐ ํฌ๊ธฐ์˜ ๋ถ€๋ถ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด ๋‚˜๊ฐ€๋ฉฐ ์ตœ์ข…์ ์œผ๋กœ ์›๋ž˜ ์ฃผ์–ด์ง„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” DP์˜ ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด

  1. ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ (Optimal Substructure)
    • ํฐ ๋ฌธ์ œ๋ฅผ ์ž‘์€ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ž‘์€ ๋ฌธ์ œ์˜ ๋‹ต์„ ๋ชจ์•„์„œ ํฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Œ
  2. ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„ ๋ฌธ์ œ (Overlapping Subproblem)
    • ๋™์ผํ•œ ์ž‘์€ ๋ฌธ์ œ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ•ด๊ฒฐํ•ด์•ผํ•จ

โœ” ๋ฉ”๋ชจ์ด์ œ์ด์…˜ (Memoization)

  • ํ•œ ๋ฒˆ ๊ณ„์‚ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ๋ฉ”๋ชจํ•˜๋Š” ๊ธฐ๋ฒ•
  • ๋‹ค์ด๋‚˜๋ฏน ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜
    • ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ”๋ชจํ–ˆ๋˜ ๊ฒฐ๊ณผ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์˜ด
    • ๊ฐ’์„ ๊ธฐ๋กํ•ด ๋†“๋Š”๋‹ค๋Š” ์ ์—์„œ ์บ์‹ฑ(Caching)์ด๋ผ๊ณ ๋„ ํ•จ
์˜ˆ์‹œ ์ฝ”๋“œ (ํ”ผ๋ณด๋‚˜์น˜)
public static int dpFibonacci(int n) {
    if (n <= 1) {
        return n;
    }

    int[] fib = new int[n+1];
    fib[0] = 0;
    fib[1] = 1;

    for (int i = 2; i <= n; i++) {
        fib[i] = fib[i-1] + fib[i-2];
    }

    return fib[n];
}
์˜ˆ์‹œ ์ฝ”๋“œ (0/1 knapsack)
// N: ๊ฐ€๋ฐฉ ํฌ๊ธฐ, K: ๋ฌด๊ฒŒ
static int knapsack(int N, int K, int[] volume, int[] price){

    dp = new int[N + 1][K + 1];

    for (int i = 0; i <= N; i++) {
        for (int j = 0; j <= K; j++) {
            if (i == 0 || j == 0) {
                dp[i][j] = 0;
            } else if (volume[i - 1] <= j) {
                dp[i][j] = Math.max(price[i - 1] + dp[i - 1][j - volume[i - 1]], dp[i - 1][j]);
            } else {
                dp[i][j] = dp[i - 1][j];
            }
        }
    }

    return dp[N][K];
}

5. ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰ / ๋ฐฑํŠธ๋ž˜ํ‚น

BFS (Breadth-First Search)

โœ” ๊ทธ๋ž˜ํ”„์—์„œ ๊ฐ€๊นŒ์šด ๋…ธ๋“œ๋ถ€ํ„ฐ ์šฐ์„ ์ ์œผ๋กœ ํƒ์ƒ‰

โœ” ํ(์„ ์ž…์„ ์ถœ) ์ž๋ฃŒ ๊ตฌ์กฐ ์‚ฌ์šฉ

โœ” ํƒ์ƒ‰ ๊ณผ์ •

  1. ํƒ์ƒ‰ ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ํ์— ์‚ฝ์ž…ํ•˜๊ณ  ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.
  2. ํ์—์„œ ๋…ธ๋“œ๋ฅผ ๊บผ๋‚ธ ๋’ค์— ํ•ด๋‹น ๋…ธ๋“œ์˜ ์ธ์ ‘ ๋…ธ๋“œ ์ค‘์—์„œ ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ๋ฅผ ๋ชจ๋‘ ํ์— ์‚ฝ์ž…ํ•˜๊ณ  ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  3. ๋” ์ด์ƒ 2๋ฒˆ์˜ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•œ๋‹ค.

โœ” (๋ชจ๋“  ๊ฐ„์„ ์˜ ๋น„์šฉ์ด ๋™์ผํ•  ๋–„) ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ

DFS (Depth-First Search)

โœ” ๊ทธ๋ž˜ํ”„์—์„œ ๊นŠ์€ ๋ถ€๋ถ„์„ ์šฐ์„ ์ ์œผ๋กœ ํƒ์ƒ‰

โœ” ์žฌ๊ท€ / ์Šคํƒ(ํ›„์ž…์„ ์ถœ) ์ž๋ฃŒ ๊ตฌ์กฐ ์‚ฌ์šฉ

โœ” ํƒ์ƒ‰ ๊ณผ์ •

  1. ํƒ์ƒ‰ ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ์Šคํƒ์— ์‚ฝ์ž…ํ•˜๊ณ  ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.
  2. ์Šคํƒ์˜ ์ตœ์ƒ๋‹จ ๋…ธ๋“œ์— ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ธ์ ‘ ๋…ธ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ ์ธ์ ‘ ๋…ธ๋“œ๋ฅผ ์Šคํƒ์— ๋„ฃ๊ณ  ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค. ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ์ธ์ ‘ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์Šคํƒ์—์„œ ์ตœ์ƒ๋‹จ ๋…ธ๋“œ๋ฅผ ๊บผ๋‚ธ๋‹ค.
  3. 2๋ฒˆ ๊ณผ์ •์„ ๋” ์ด์ƒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์„ ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•œ๋‹ค.

โœ” ๋ฐฑํŠธ๋ž˜ํ‚น / ๋ชจ๋“  ๊ฒฝ์šฐ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ๋‹ค ํƒ์ƒ‰ํ•˜๋Š” ๊ฒฝ์šฐ ์ฃผ๋กœ ์‚ฌ์šฉ

BFS vs DFS

โœ” ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๋‘˜๋‹ค O(V + E)๋กœ ๋™์ผ


์ถœ์ฒ˜: ๋ฐ”ํ‚น๋… ๋ธ”๋กœ๊ทธ

์˜ˆ์‹œ ์ฝ”๋“œ
import java.util.*;

public class Graph {
    private int V;
    private LinkedList<Integer>[] adj;

    // ๊ทธ๋ž˜ํ”„ ๊ตฌํ˜„
    public Graph(int v) {
        V = v;
        adj = new LinkedList[v];
        for (int i = 0; i < v; i++) {
            adj[i] = new LinkedList<>();
        }
    }

    public void addEdge(int v, int w) {
        adj[v].add(w);
    }


    // BFS (ํ ์‚ฌ์šฉ)
    public void bfs(int s) {
        boolean[] visited = new boolean[V];
        LinkedList<Integer> queue = new LinkedList<>();
        visited[s] = true;
        queue.add(s);

        while (!queue.isEmpty()) {
            s = queue.poll();
            System.out.print(s + " ");

            Iterator<Integer> i = adj[s].listIterator();
            while (i.hasNext()) {
                int n = i.next();
                if (!visited[n]) {
                    visited[n] = true;
                    queue.add(n);
                }
            }
        }
    }


    // DFS (์žฌ๊ท€ ์‚ฌ์šฉ)
    public void dfs(int v) {
        boolean[] visited = new boolean[V];
        dfsUtil(v, visited);
    }

    private void dfsUtil(int v, boolean[] visited) {
        visited[v] = true;
        System.out.print(v + " ");

        Iterator<Integer> i = adj[v].listIterator();
        while (i.hasNext()) {
            int n = i.next();
            if (!visited[n]) {
                dfsUtil(n, visited);
            }
        }
    }

    public static void main(String[] args) {
        Graph g = new Graph(4);

        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);

        System.out.print("BFS traversal starting from vertex 2: ");
        g.bfs(2); // "BFS traversal starting from vertex 2: 2 0 3 1"

        System.out.print("\nDFS traversal starting from vertex 2: ");
        g.dfs(2); // "DFS traversal starting from vertex 2: 2 0 1 3"
    }
}

6. ๊ทธ๋ž˜ํ”„ ์‹ฌํ™”

๋ฒจ๋งŒํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” (๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„์—์„œ) ํ•œ ๋…ธ๋“œ์—์„œ ๋‹ค๋ฅธ ๋…ธ๋“œ๊นŒ์ง€์˜ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” (๋‹ค์ต์ŠคํŠธ๋ผ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ) ๊ฐ„์„ ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ์Œ์ˆ˜์ผ ๋•Œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

โœ” ๋ชจ๋“  ๊ฐ„์„ ์„ ํƒ์ƒ‰ํ•˜๋ฉด์„œ ์ธ์ ‘ํ•œ ์ •์ ์— ๋Œ€ํ•œ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ฐฑ์‹  (Edge relaxation)

โœ” ์‹œ๊ฐ„ ๋ณต์žก๋„: O(VE)

โœ” ํƒ์ƒ‰ ๊ณผ์ •

  1. ์ถœ๋ฐœ์ ์—์„œ ๋ชจ๋“  ์ •์ ๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ๋ฅผ ์ €์žฅํ•˜๋Š” dist[] ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค. (dist[start] = 0, dist[v] = ๋ฌดํ•œ๋Œ€)
  2. ๊ทธ๋ž˜ํ”„์˜ ๋ชจ๋“  ์ •์  u์— ๋Œ€ํ•ด, ๋‹ค์Œ ๊ณผ์ •์„ V-1๋ฒˆ ๋ฐ˜๋ณตํ•ด ์ˆ˜ํ–‰ํ•œ๋‹ค:
    • ๊ทธ๋ž˜ํ”„์˜ ๋ชจ๋“  ๊ฐ„์„ (u, v)์— ๋Œ€ํ•ด, dist[u] + weight(u, v) < dist[v]์ด๋ฉด, dist[v]๋ฅผ ์ƒˆ๋กœ์šด, ๋” ์งง์€ ๊ฑฐ๋ฆฌ๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
  3. ๊ทธ๋ž˜ํ”„์—์„œ ์Œ์˜ ๊ฐ€์ค‘์น˜ ์‚ฌ์ดํด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.(์Œ์˜ ๊ฐ€์ค‘์น˜ ์‚ฌ์ดํด์ด ์กด์žฌํ•  ์‹œ ์ œ๋Œ€๋กœ ํƒ์ƒ‰ํ•˜์ง€ ๋ชปํ•œ๋‹ค)
  4. ์ถœ๋ฐœ์ ์—์„œ ๋ชจ๋“  ์ •์ ๊นŒ์ง€์˜ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” dist[] ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ์‹œ ์ฝ”๋“œ
import java.util.Arrays;

public class BellmanFord {
    private int V, E;
    private Edge[] edges;

    // ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ์ž
    public BellmanFord(int v, int e) {
        V = v;
        E = e;
        edges = new Edge[e];
    }

    public void addEdge(int src, int dest, int weight, int i) {
        edges[i] = new Edge(src, dest, weight);
    }


    // ๋ฒจ๋งŒํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜
    public void bellmanFord(int src) {

        // ์ตœ์†Œ ๊ฑฐ๋ฆฌ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”
        int[] dist = new int[V];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[src] = 0;

        // ๋ชจ๋“  ์—ฃ์ง€์— ๋Œ€ํ•ด ์ตœ์†Ÿ๊ฐ’ ๊ฐฑ์‹ 
        for (int i = 1; i < V; i++) {
            for (int j = 0; j < E; j++) {
                int u = edges[j].src;
                int v = edges[j].dest;
                int weight = edges[j].weight;
                if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {
                    dist[v] = dist[u] + weight;
                }
            }
        }

        // ์Œ์˜ ๊ฐ€์ค‘์น˜ ์‚ฌ์ดํด ํ™•์ธ      
        for (int i = 0; i < E; i++) {
            int u = edges[i].src;
            int v = edges[i].dest;
            int weight = edges[i].weight;
            if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {
                System.out.println("Negative weight cycle detected");
                return;
            }
        }

        printDistances(src, dist);
    }

    // ๊ฒฐ๊ณผ๊ฐ’ ์ถœ๋ ฅ

    private void printDistances(int src, int[] dist) {
        System.out.println("Shortest distances from source vertex " + src + " to all vertices:");
        for (int i = 0; i < V; i++) {
            System.out.println("Vertex " + i + ": " + dist[i]);
        }
    }

    public static void main(String[] args) {
        int V = 5;
        int E = 8;
        BellmanFord graph = new BellmanFord(V, E);
        graph.addEdge(0, 1, -1, 0);
        graph.addEdge(0, 2, 4, 1);
        graph.addEdge(1, 2, 3, 2);
        graph.addEdge(1, 3, 2, 3);
        graph.addEdge(1, 4, 2, 4);
        graph.addEdge(3, 2, 5, 5);
        graph.addEdge(3, 1, 1, 6);
        graph.addEdge(4, 3, -3, 7);

        int source = 0;
        graph.bellmanFord(source); 

        // Shortest distances from source vertex 0 to all vertices:
        // Vertex 0: 0
        // Vertex 1: -1
        // Vertex 2: 2
        // Vertex 3: -2
        // Vertex 4: 1
    }
}


// ๊ฐ„์„  ํด๋ž˜์Šค
class Edge {
    int src, dest, weight;

    public Edge(int src, int dest, int weight) {
        this.src = src;
        this.dest = dest;
        this.weight = weight;
    }
}

๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ์Œ์˜ ๊ฐ€์ค‘์น˜๊ฐ€ ์—†๋Š” ๊ทธ๋ž˜ํ”„์˜ ํ•œ ์ •์ ์—์„œ ๋ชจ๋“  ์ •์ ๊นŒ์ง€์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ๊ฐ ๊ตฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ํƒ์ƒ‰๊ณผ์ •

  1. ์ถœ๋ฐœ์ ์œผ๋กœ๋ถ€ํ„ฐ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ์ €์žฅํ•  ๋ฐฐ์—ด distance[v]์„ ๋งŒ๋“ค๊ณ  ์ถœ๋ฐœ ๋…ธ๋“œ๋Š” 0, ๋‚˜๋จธ์ง€ ๋…ธ๋“œ๋“ค์€ ์ถฉ๋ถ„ํžˆ ํฐ ๊ฐ’์œผ๋กœ ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.
  2. ํ˜„์žฌ ๋…ธ๋“œ Current๋ฅผ ์ถœ๋ฐœ ๋…ธ๋“œ์˜ ๋ฒˆํ˜ธ๋กœ ์„ค์ •ํ•œ๋‹ค.
  3. Current๋กœ๋ถ€ํ„ฐ ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์ž„์˜์˜ ๋…ธ๋“œ Next์— ๋Œ€ํ•ด distance[Current] + P[Current][Next](A๋ฅผ ๊ฑฐ์ณ์„œ B๋กœ ๊ฐ€๋Š” ์ตœ๋‹จ๊ฑฐ๋ฆฌ)์™€ distance[Next](ํ˜„์žฌ๊นŒ์ง€ ์•Œ๋ ค์ง„ B์˜ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ)์˜ ๊ฐ’์„ ๋น„๊ตํ•ด์„œ ์งง์€ ๊ฐ’(์งง์€ ๊ฒฝ๋กœ)๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
  4. Current์˜ ๋ชจ๋“  ์ด์›ƒ๋…ธ๋“œ Next์— ๋Œ€ํ•ด 3 ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  5. Current์˜ ์ƒํƒœ๋ฅผ ‘visited=True’๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค. (Current๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.)
  6. visited == False์ธ ๋…ธ๋“œ ์ค‘ ์ถœ๋ฐœ์ ์œผ๋กœ๋ถ€ํ„ฐ ๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ์งง์€ ๋…ธ๋“œ๋ฅผ Current๋กœ ์„ค์ •ํ•œ๋‹ค.
  7. ๋„์ฐฉ ๋…ธ๋“œ๊ฐ€ 'visited == True’๊ฐ€ ๋˜๊ฑฐ๋‚˜, ๋” ์ด์ƒ ๋ฏธ๋ฐฉ๋ฌธ ๋…ธ๋“œ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์—†์„ ๋•Œ๊นŒ์ง€ 3 ~ 6์˜ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•œ๋‹ค

โœ” ์‹œ๊ฐ„ ๋ณต์žก๋„: O(V^2)

โœ” ์šฐ์„ ์ˆœ์œ„ํ๋ฅผ ์ด์šฉํ•ด ๋ฐ”๋กœ ๋‹ค์Œ ๋…ธ๋“œ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•ด๋‚ด์„œ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค -> ์‹œ๊ฐ„ ๋ณต์žก๋„ O(ElogE)

์˜ˆ์‹œ ์ฝ”๋“œ
import java.util.*;

public class Dijkstra {
    private int V;
    private List<Edge>[] adj;

    // ๊ทธ๋ž˜ํ”„(์ธ์ ‘๋ฆฌ์ŠคํŠธ) ํด๋ž˜์Šค ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”
    public Dijkstra(int v) {
        V = v;
        adj = new ArrayList[v];
        for (int i = 0; i < v; i++) {
            adj[i] = new ArrayList<>();
        }
    }

    public void addEdge(int src, int dest, int weight) {
        adj[src].add(new Edge(dest, weight));
        adj[dest].add(new Edge(src, weight));
    }


    // ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ (์šฐ์„ ์ˆœ์œ„ํ)
    public void dijkstra(int src) {

        PriorityQueue<Node> pq = new PriorityQueue<>();

        // ์ตœ๋‹จ๊ฑฐ๋ฆฌ ํ…Œ์ด๋ธ” ์ดˆ๊ธฐํ™”
        int[] dist = new int[V];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[src] = 0;
        pq.add(new Node(src, 0));


        while (!pq.isEmpty()) {
            int u = pq.poll().vertex;

            // ์šฐ์„ ์ˆœ์œ„ํ ์ด์šฉํ•ด ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ๊ฐฑ์‹ 
            for (Edge e : adj[u]) {
                int v = e.dest;
                int weight = e.weight;
                if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) {
                    dist[v] = dist[u] + weight;
                    pq.add(new Node(v, dist[v]));
                }
            }
        }

        printDistances(src, dist);
    }

    // ๊ฒฐ๊ณผ๊ฐ’ ์ถœ๋ ฅ
    private void printDistances(int src, int[] dist) {
        System.out.println("Shortest distances from source vertex " + src + " to all vertices:");
        for (int i = 0; i < V; i++) {
            System.out.println("Vertex " + i + ": " + dist[i]);
        }
    }

    public static void main(String[] args) {
        int V = 5;
        Dijkstra graph = new Dijkstra(V);
        graph.addEdge(0, 1, 9);
        graph.addEdge(0, 2, 6);
        graph.addEdge(0, 3, 5);
        graph.addEdge(0, 4, 3);
        graph.addEdge(2, 1, 2);
        graph.addEdge(2, 3, 4);

        int source = 0;
        graph.dijkstra(source);

        // Shortest distances from source vertex 0 to all vertices:
        // Vertex 0: 0
        // Vertex 1: 7
        // Vertex 2: 6
        // Vertex 3: 5
        // Vertex 4: 3
    }
}


// ์—ฃ์ง€๋ž‘ ๋…ธ๋“œ ํด๋ž˜์Šค ์ •์˜
class Edge {
    int dest, weight;

    public Edge(int dest, int weight) {
        this.dest = dest;
        this.weight = weight;
    }
}

class Node implements Comparable<Node> {
    int vertex, dist;

    public Node(int vertex, int dist) {
        this.vertex = vertex;
        this.dist = dist;
    }

    public int compareTo(Node other) {
        return Integer.compare(dist, other.dist);
    }
}

7. ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ (Minimum Spanning Tree)

โœ” ์‹ ์žฅํŠธ๋ฆฌ: ๊ทธ๋ž˜ํ”„ ๋‚ด์˜ ๋ชจ๋“  ์ •์ ์„ ํฌํ•จํ•˜๋Š” ํŠธ๋ฆฌ

โœ” ์ตœ์†Œ ์‹ ์žฅํŠธ๋ฆฌ Spanning Tree ์ค‘์—์„œ ๊ฐ„์„ ์˜ ๊ฐ€์ค‘์น˜ ํ•ฉ์ด ์ตœ์†Œ(Minimun)์ธ ํŠธ๋ฆฌ

๊ตฌํ˜„: ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” Greedy๋ฅผ ์ด์šฉํ•ด ๊ฐ ๋‹จ๊ณ„์—์„œ ์‚ฌ์ดํด์„ ์ด๋ฃจ์ง€ ์•Š๋Š” ์ตœ์†Œ ๋น„์šฉ ๊ฐ„์„ ์„ ์„ ํƒํ•œ๋‹ค.

โœ” ํƒ์ƒ‰ ๊ณผ์ •

  1. ๊ฐ„์„ ์„ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•œ๋‹ค. (์ตœ์†Œ ๋น„์šฉ)
  2. ์ •๋ ฌ๋œ ๊ฐ„์„  ๋ฆฌ์ŠคํŠธ์—์„œ ์ˆœ์„œ๋Œ€๋กœ ์‚ฌ์ดํด์„ ํ˜•์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฐ„์„ ์„ ์„ ํƒํ•œ๋‹ค. (์œ ๋‹ˆ์˜จ ํŒŒ์ธ๋“œ)
  3. ์„ ํƒํ•œ ๊ฐ„์„ ์„ ํ˜„์žฌ MST์ง‘ํ•ฉ์— ์ถ”๊ฐ€ํ•œ๋‹ค
์˜ˆ์‹œ ์ฝ”๋“œ
import java.util.*;

public class KruskalMST {
    private int V, E;
    private List<Edge> edges;

    // ๊ทธ๋ž˜ํ”„ ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”
    public KruskalMST(int v, int e) {
        V = v;
        E = e;
        edges = new ArrayList<>();
    }

    public void addEdge(int src, int dest, int weight) {
        edges.add(new Edge(src, dest, weight));
    }

    public int kruskalMST() {
        // parent ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”
        int cost = 0;
        int[] parent = new int[V];
        Arrays.fill(parent, -1);

        // ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ ๊ฐฑ์‹ 
        for (Edge e : edges) {
            // ์‚ฌ์ดํด ํŒ๋ณ„
            int root1 = find(parent, e.src);
            int root2 = find(parent, e.dest);

            if (root1 != root2) {
                // ๋น„์šฉ ๊ณ„์‚ฐ
                cost += e.weight;
                // ์œ ๋‹ˆ์˜จ
                parent[root1] = root2;
            }
        }

        return cost;
    }


    // ํŒŒ์ธ๋“œ ํ•จ์ˆ˜(์‚ฌ์ดํด ํŒ๋ณ„)
    private int find(int[] parent, int v) {
        if (parent[v] < 0) {
            return v;
        }
        parent[v] = find(parent, parent[v]);
        return parent[v];
    }

    public static void main(String[] args) {
        int V = 5;
        int E = 7;
        KruskalMST graph = new KruskalMST(V, E);
        graph.addEdge(0, 1, 2);
        graph.addEdge(0, 3, 6);
        graph.addEdge(1, 2, 3);
        graph.addEdge(1, 3, 8);
        graph.addEdge(1, 4, 5);
        graph.addEdge(2, 4, 7);
        graph.addEdge(3, 4, 9);

        int cost = graph.kruskalMST();
        System.out.println("Total cost of the Minimum Spanning Tree: " + cost);
        // Total cost of the Minimum Spanning Tree: 16
    }
}

// ๊ฐ„์„  ํด๋ž˜์Šค ์ •์˜
class Edge implements Comparable<Edge> {
    int src, dest, weight;

    public Edge(int src, int dest, int weight) {
        this.src = src;
        this.dest = dest;
        this.weight = weight;
    }

    public int compareTo(Edge other) {
        return Integer.compare(weight, other.weight);
    }
}

8. ๋ถ„ํ• ์ •๋ณต / ์ด๋ถ„ํƒ์ƒ‰

๋ถ„ํ• ์ •๋ณต

โœ” ๋ฌธ์ œ๋ฅผ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์„ ๋•Œ๊นŒ์ง€ ๋‚˜๋ˆ„์–ด์„œ ๊ฐ๊ฐ์„ ํ’€๋ฉด์„œ ๋‹ค์‹œ ํ•ฉ๋ณ‘ํ•˜์—ฌ ๋ฌธ์ œ์˜ ๋‹ต์„ ์–ป๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ์ฃผ๋กœ ์žฌ๊ท€ ํ™œ์šฉ

โœ” ์˜ˆ์‹œ: ๋ณ‘ํ•ฉ์ •๋ ฌ, ํ€ต์ •๋ ฌ, ์ด๋ถ„ํƒ์ƒ‰...

๋ถ„ํ• ์ •๋ณต vs DP

โœ” ๋ถ„ํ•  ์ •๋ณต์€ ๋ถ„ํ• ๋œ ํ•˜์œ„ ๋ฌธ์ œ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ์ค‘๋ณต์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ์“ฐ๋ฉฐ, ๋™์ผํ•œ ์ค‘๋ณต์ด ์ผ์–ด๋‚˜๋ฉด ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ™œ์šฉ(๋ฉ”๋ชจ์ด์ œ์ด์…˜)

์ด๋ถ„ํƒ์ƒ‰ (Binary Search)

โœ” (์ฃผ๋กœ ์ •๋ ฌ๋œ ๋ฐ์ดํ„ฐ์—์„œ) ๊ฒ€์ƒ‰ ๋ฒ”์œ„๋ฅผ ๋ฐ˜์œผ๋กœ ์ค„์—ฌ ๋‚˜๊ฐ€๋ฉด์„œ ๊ฒ€์ƒ‰ ๊ฐ’์„ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ์ƒ‰(Parametric search)์—์„œ ํ™œ์šฉ ๊ฐ€๋Šฅ!

โœ” ์‹œ๊ฐ„ ๋ณต์žก๋„: O(logN)

์˜ˆ์‹œ ์ฝ”๋“œ
public class BinarySearch {

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

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9};
        int target = 7;
        int index = binarySearch(arr, target);
        if (index == -1) {
            System.out.println("Target not found in array");
        } else {
            System.out.println("Target found at index " + index);
        }
    }
}

9. ๊ทธ๋ฆฌ๋””

โœ” ์—ฌ๋Ÿฌ ๊ฒฝ์šฐ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฒฐ์ •ํ•ด์•ผ ํ•  ๋•Œ๋งˆ๋‹ค ๊ทธ ์ˆœ๊ฐ„์— ์ตœ์ ์ด๋ผ๊ณ  ์ƒ๊ฐ๋˜๋Š” ๊ฒƒ์„ ์„ ํƒํ•ด ๋‚˜๊ฐ€๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ํ•˜์—ฌ ์ตœ์ข…์ ์ธ ํ•ด๋‹ต์— ๋„๋‹ฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜

โœ” ๊ทธ๋ฆฌ๋””์˜ ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด

  1. ํƒ์š•์Šค๋Ÿฐ ์„ ํƒ ์กฐ๊ฑด(greedy choice property)๊ณผ
    • ์•ž์˜ ์„ ํƒ์ด ์ดํ›„์˜ ์„ ํƒ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค
  2. ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ ์กฐ๊ฑด(optimal substructure)
    • ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ตœ์ ํ•ด๊ฐ€ ๋ถ€๋ถ„๋ฌธ์ œ์— ๋Œ€ํ•ด์„œ๋„ ์—ญ์‹œ ์ตœ์ ํ•ด์ด๋‹ค.
์˜ˆ์‹œ ์ฝ”๋“œ (๋ƒ…์ƒ‰)
import java.util.Arrays;

public class FractionalKnapsack {

    // ๊ทธ๋ฆฌ๋””๋กœ ๋ฐฐ๋‚ญ ์ฑ„์›Œ๋„ฃ๊ธฐ
    public static double getMaximumValue(int[] weights, int[] values, int capacity) {
        int n = weights.length;
        double[] ratios = new double[n]; // ๊ฐ€์น˜/๋ฌด๊ฒŒ ๋น„์œจ

        // ๋น„์œจ ๊ตฌํ•˜๊ธฐ
        for (int i = 0; i < n; i++) {
            ratios[i] = (double) values[i] / weights[i];
        }

        // ๋ฌผ๊ฑด ์ •๋ณด
        Item[] items = new Item[n];

        for (int i = 0; i < n; i++) {
            items[i] = new Item(weights[i], values[i], ratios[i]);
        }

        // ์ •๋ ฌ
        Arrays.sort(items);

        double maximumValue = 0;

        // ๊ทธ๋ฆฌ๋””ํ•˜๊ฒŒ ๋ฌผ๊ฑด ์ฑ„์›Œ ๋„ฃ๊ธฐ
        for (int i = n - 1; i >= 0; i--) {
            if (capacity == 0) {
                break;
            }

            double weightToAdd = Math.min(items[i].getWeight(), capacity);
            maximumValue += weightToAdd * items[i].getRatio();
            capacity -= weightToAdd;
        }

        return maximumValue;
    }

    public static void main(String[] args) {
        int[] weights = {10, 20, 30};
        int[] values = {60, 100, 120};
        int capacity = 50;

        double maximumValue = getMaximumValue(weights, values, capacity);
        System.out.println("Maximum value we can obtain = " + maximumValue); // prints "Maximum value we can obtain = 240.0"
    }
}

// ํด๋ž˜์Šค ์ •์˜
class Item implements Comparable<Item> {
    private int weight;
    private int value;
    private double ratio;

    public Item(int weight, int value, double ratio) {
        this.weight = weight;
        this.value = value;
        this.ratio = ratio;
    }

    public int getWeight() {
        return weight;
    }

    public int getValue() {
        return value;
    }

    public double getRatio() {
        return ratio;
    }

    @Override
    public int compareTo(Item item) {
        return Double.compare(this.ratio, item.ratio);
    }
}

๋Œ“๊ธ€