16. ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜ (Greedy Algorithms) Codility Lesson ํ•œ๊ตญ์–ด ์ •๋ฆฌ๋ณธ (JavaScript ver.)

    ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜(Greedy Algorithm)์ด๋ž€?

    ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ ๋‹จ๊ณ„์—์„œ ๊ฐ€์žฅ ์ตœ์„ ์˜ ์„ ํƒ์„ ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ตœ์ ํ•ด๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ• ์ด๋‹ค. ์ „์ฒด ์ตœ์ ํ•ด๋ฅผ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ , ๋งค ์ˆœ๊ฐ„ ์ตœ์ ์˜ ์„ ํƒ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ํ•ญ์ƒ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

    ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ๋Œ€ํ‘œ์ ์ธ ๋ฌธ์ œ๋“ค:

    • ๋™์ „ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ (Coin Change Problem)
    • ํšŒ์˜์‹ค ๋ฐฐ์ • ๋ฌธ์ œ (Activity Selection Problem)
    • ๋ฐฐ๋‚ญ ๋ฌธ์ œ (Knapsack Problem)
    • ์ž‘์—… ์Šค์ผ€์ค„๋ง ๋ฌธ์ œ (Activity Selection)
    • ์ตœ์†Œ ์‹ ์žฅ ํŠธ๋ฆฌ (MST, Minimum Spanning Tree)
    • ํ—ˆํ”„๋งŒ ์ฝ”๋”ฉ (Huffman Coding)

    ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํŠน์ง•

    • ๋น ๋ฅธ ์‹คํ–‰ ์‹œ๊ฐ„: O(n log n) ๋˜๋Š” O(n)๋กœ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ
    • ๊ตญ์†Œ์  ์ตœ์ ํ•ด ๊ธฐ๋ฐ˜: ํ˜„์žฌ ์ƒํƒœ์—์„œ ๊ฐ€์žฅ ์ข‹์€ ์„ ํƒ์„ ํ•œ๋‹ค.
    • ์ตœ์ ํ•ด๋ฅผ ํ•ญ์ƒ ๋ณด์žฅํ•˜์ง€ ์•Š์Œ: ๋™์ „ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ์ฒ˜๋Ÿผ ์ผ๋ถ€ ๊ฒฝ์šฐ์—๋Š” ์ตœ์ ํ•ด๋ฅผ ๊ตฌํ•  ์ˆ˜ ์—†๋‹ค.

    4. ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ํ•œ๊ณ„

    ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋งค ์ˆœ๊ฐ„ ์ตœ์ ์˜ ์„ ํƒ์„ ํ•˜์ง€๋งŒ, ํ•ญ์ƒ ์ „์ฒด ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค:

    • ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ(Otimal Substructure) ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ (์˜ˆ: ๋ฐฐ๋‚ญ ๋ฌธ์ œ, ์ผ๋ถ€ ๋™์ „ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ)
    • ๊ฒฐ์ •ํ•ด์•ผ ํ•  ์š”์†Œ๋“ค์ด ์„œ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” ๊ฒฝ์šฐ

    ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์—์„œ๋Š” ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(DP)์ด๋‚˜ ๋ฐฑํŠธ๋ž˜ํ‚น(Backtracking) ๊ฐ™์€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.


    1. O(n) ์‹œ๊ฐ„ ๋ณต์žก๋„์˜ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ ํ•ด๊ฒฐ

    ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ๋Š” ์ฃผ์–ด์ง„ ๋™์ „๋“ค๋กœ ํŠน์ • ๊ธˆ์•ก์„ ์ตœ์†Œ ๊ฐœ์ˆ˜์˜ ๋™์ „์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฌธ์ œ ์ด๋‹ค. ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ€์žฅ ํฐ ๋™์ „๋ถ€ํ„ฐ ์„ ํƒํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

    JavaScript ์ฝ”๋“œ:

    function coinChange(coins, amount) {
        coins.sort((a, b) => b - a); // ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
        let count = 0;
        
        for (let coin of coins) {
            while (amount >= coin) {
                amount -= coin;
                count++;
            }
        }
        return amount === 0 ? count : -1;
    }
    

    ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n) (๋™์ „ ๊ฐœ์ˆ˜๋งŒํผ ๋ฐ˜๋ณต)

    ์ฃผ์˜: ์ด ๋ฐฉ๋ฒ•์€ ํ•ญ์ƒ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋™์ „์ด [1, 3, 4]์ด๊ณ  amount = 6์ผ ๋•Œ, ํƒ์š•์  ์ ‘๊ทผ๋ฒ•์€ [4, 1, 1]์„ ์„ ํƒํ•˜์ง€๋งŒ, ์ตœ์ ํ•ด๋Š” [3, 3]์ด๋‹ค.


    2. O(n log n) ์‹œ๊ฐ„ ๋ณต์žก๋„์˜ ํšŒ์˜์‹ค ๋ฐฐ์ • ๋ฌธ์ œ

    ํšŒ์˜์‹ค ๋ฐฐ์ • ๋ฌธ์ œ๋Š” ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ํšŒ์˜๋ฅผ ์ˆ˜์šฉํ•˜๊ธฐ ์œ„ํ•ด, ํšŒ์˜๊ฐ€ ๊ฒน์น˜์ง€ ์•Š๋„๋ก ๋ฐฐ์ •ํ•˜๋Š” ๋ฌธ์ œ ์ด๋‹ค. ์ข…๋ฃŒ ์‹œ๊ฐ„์ด ๊ฐ€์žฅ ๋น ๋ฅธ ํšŒ์˜๋ถ€ํ„ฐ ์„ ํƒํ•˜๋ฉด ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

    JavaScript ์ฝ”๋“œ:

    function maxMeetings(start, end) {
        let n = start.length;
        let meetings = [];
        
        for (let i = 0; i < n; i++) {
            meetings.push([start[i], end[i]]);
        }
        
        meetings.sort((a, b) => a[1] - b[1]); // ์ข…๋ฃŒ ์‹œ๊ฐ„ ๊ธฐ์ค€ ์ •๋ ฌ
        
        let count = 0, lastEnd = 0;
        for (let [s, e] of meetings) {
            if (s >= lastEnd) {
                count++;
                lastEnd = e;
            }
        }
        return count;
    }
    

    ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n) (์ •๋ ฌ ํ›„ ์„ ํ˜• ํƒ์ƒ‰)


    3. O(E log V) ์‹œ๊ฐ„ ๋ณต์žก๋„์˜ ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

    ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜(Dijkstra’s Algorithm)์€ ๊ฐ€์ค‘์น˜๊ฐ€ ์žˆ๋Š” ๊ทธ๋ž˜ํ”„์—์„œ ์ถœ๋ฐœ์ ์œผ๋กœ๋ถ€ํ„ฐ ๋ชจ๋“  ์ •์ ๊นŒ์ง€์˜ ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ์ฐพ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ด๋‹ค. ํƒ์š•์  ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งค ๋‹จ๊ณ„์—์„œ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ์„ ํƒํ•œ๋‹ค.

    JavaScript ์ฝ”๋“œ:

    class PriorityQueue {
        constructor() {
            this.queue = [];
        }
        enqueue(value, priority) {
            this.queue.push({ value, priority });
            this.queue.sort((a, b) => a.priority - b.priority);
        }
        dequeue() {
            return this.queue.shift().value;
        }
        isEmpty() {
            return this.queue.length === 0;
        }
    }
    
    function dijkstra(graph, start) {
        let distances = {};
        let pq = new PriorityQueue();
        
        for (let node in graph) {
            distances[node] = Infinity;
        }
        distances[start] = 0;
        pq.enqueue(start, 0);
        
        while (!pq.isEmpty()) {
            let current = pq.dequeue();
            for (let neighbor in graph[current]) {
                let newDist = distances[current] + graph[current][neighbor];
                if (newDist < distances[neighbor]) {
                    distances[neighbor] = newDist;
                    pq.enqueue(neighbor, newDist);
                }
            }
        }
        return distances;
    }
    

    ์‹œ๊ฐ„ ๋ณต์žก๋„: O(E log V) (์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ์ด์šฉํ•œ ๊ตฌํ˜„)

     

    4. ์นด๋ˆ„ ๋ฌธ์ œ (Canoeist Problem)

    ๋ฌธ์ œ

    ๋ฌด๊ฒŒ๊ฐ€ ๋‹ค๋ฅธ n๋ช…์˜ ์นด๋ˆ„ ์„ ์ˆ˜๊ฐ€ ์žˆ๊ณ , ๊ฐ ์นด๋ˆ„์—๋Š” ์ตœ๋Œ€ ๋‘ ๋ช…๊นŒ์ง€ ํƒˆ ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋“  ์„ ์ˆ˜๋ฅผ ์ตœ์†Œํ•œ์˜ ์นด๋ˆ„์— ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด ๋ชฉํ‘œ์ด๋‹ค.

    ์ ‘๊ทผ ๋ฐฉ๋ฒ•

    • ๊ฐ€์žฅ ๋ฌด๊ฑฐ์šด ์„ ์ˆ˜(heavy)๋ฅผ ์ฐพ๊ณ , ํ•จ๊ป˜ ํƒˆ ์ˆ˜ ์žˆ๋Š” ๊ฐ€์žฅ ๋ฌด๊ฑฐ์šด ๊ฐ€๋ฒผ์šด ์„ ์ˆ˜(light)๋ฅผ ์ฐพ๋Š”๋‹ค.
    • ๋ฌด๊ฑฐ์šด ์„ ์ˆ˜์™€ ๊ฐ€๋ฒผ์šด ์„ ์ˆ˜๋ฅผ ํ•จ๊ป˜ ํƒœ์šด๋‹ค.
    • ์œ„ ๊ณผ์ •์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ๋ฌด๊ฑฐ์šด ์„ ์ˆ˜๋งŒ ๋”ฐ๋กœ ํƒœ์šด๋‹ค.

    JavaScript ์ฝ”๋“œ (ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜)

    function greedyCanoeist(weights, maxWeight) { 
    	weights.sort((a, b) => a - b); // ๋ฌด๊ฒŒ ๊ธฐ์ค€ ์ •๋ ฌ 
        let canoes = 0; 
        let i = 0, j = weights.length - 1; 
        while (i <= j) { 
        	if (weights[i] + weights[j] <= maxWeight) { 
            	i++; // ๊ฐ€๋ฒผ์šด ์‚ฌ๋žŒ๊ณผ ํ•จ๊ป˜ ํƒœ์šด๋‹ค. 
            } j--; // ๋ฌด๊ฑฐ์šด ์‚ฌ๋žŒ์€ ๋ฌด์กฐ๊ฑด ํƒœ์›€ 
            canoes++; 
        } 
        return canoes; 
    }

    ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n log n) (์ •๋ ฌ) + O(n) (ํƒ์ƒ‰) = O(n log n)


    5. ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ฆ๋ช… (Greedy Algorithm Proof)

    ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ•ญ์ƒ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•˜๋ ค๋ฉด, ์„ ํƒํ•œ ๊ฒฐ์ •์ด ์ „์ฒด ๋ฌธ์ œ์—์„œ๋„ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ•™์  ๊ท€๋‚ฉ๋ฒ•์œผ๋กœ ์ฆ๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.

    1. ์ฒซ ๋ฒˆ์งธ ์„ ํƒ์ด ์ตœ์ ํ•ด์˜ ์ผ๋ถ€๋ผ๋ฉด, ๋‚˜๋จธ์ง€ ๋ฌธ์ œ๋„ ์ตœ์ ํ•ด๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    2. ๊ธฐ์กด์˜ ์ตœ์ ํ•ด์—์„œ ์ฒซ ๋ฒˆ์งธ ์„ ํƒ์„ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๋ฐ”๊พธ์–ด๋„ ๋™์ผํ•œ ์„ฑ๋Šฅ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    3. ๋งŒ์•ฝ ๋ฐ”๊ฟจ์„ ๋•Œ ๋” ๋‚˜์€ ํ•ด๋‹ต์ด ๋‚˜์˜จ๋‹ค๋ฉด, ํƒ์š•์  ์„ ํƒ์ด ์ž˜๋ชป๋˜์—ˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

    ์œ„ ์ฆ๋ช…์ด ์„ฑ๋ฆฝํ•˜๋ฉด ํƒ์š• ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด๋„ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

     

    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€