17. ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ (Dynamic Programming) Codility Lesson ํ•œ๊ตญ์–ด ์ •๋ฆฌ๋ณธ (JavaScript ver.)

    ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Dynamic Programming)์ด๋ž€?

    ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(DP)์€ ์ž‘์€ ๋ฌธ์ œ๋“ค์˜ ํ•ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋” ํฐ ๋ฌธ์ œ์˜ ํ•ด๋ฅผ ๊ตฌํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ธฐ๋ฒ• ์ด๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฌธ์ œ๋ฅผ ์—ฌ๋Ÿฌ ์ž‘์€ ๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„๊ณ , ์ค‘๋ณต ๊ณ„์‚ฐ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅ(memoization) ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

    ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ํšจ๊ณผ์ ์ธ ๊ฒฝ์šฐ:

    • ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ(Optimal Substructure): ํฐ ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๊ฐ€ ์ž‘์€ ๋ถ€๋ถ„ ๋ฌธ์ œ์˜ ์ตœ์ ํ•ด๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์Œ
    • ์ค‘๋ณต ๋ถ€๋ถ„ ๋ฌธ์ œ(Overlapping Subproblems): ๋™์ผํ•œ ์ž‘์€ ๋ฌธ์ œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

    ๋Œ€ํ‘œ์ ์ธ DP ๋ฌธ์ œ:

    • ์ตœ๋‹จ ๊ฒฝ๋กœ ๋ฌธ์ œ (Floyd-Warshall, Bellman-Ford)
    • ๋ฐฐ๋‚ญ ๋ฌธ์ œ (Knapsack Problem)
    • ๋™์ „ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ (Coin Change Problem)
    • ๊ณ„๋‹จ ์˜ค๋ฅด๊ธฐ ๋ฌธ์ œ (Climbing Stairs)
    • ์ตœ์žฅ ๊ณตํ†ต ๋ถ€๋ถ„ ์ˆ˜์—ด (LCS, Longest Common Subsequence)

    1. ๋™์ „ ๊ฑฐ์Šค๋ฆ„๋ˆ ๋ฌธ์ œ (Coin Change Problem)

    ๋ฌธ์ œ ์„ค๋ช…

    ์ฃผ์–ด์ง„ ๋™์ „ ์„ธํŠธ์—์„œ ํŠน์ • ๊ธˆ์•ก์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ตœ์†Œ ๋™์ „ ๊ฐœ์ˆ˜๋ฅผ ์ฐพ๋Š” ๋ฌธ์ œ์ด๋‹ค. ํƒ์š•์  ์•Œ๊ณ ๋ฆฌ์ฆ˜(Greedy Algorithm) ์€ ํ•ญ์ƒ ์ตœ์ ํ•ด๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, DP๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ตœ์ ํ•ด๋ฅผ ์ฐพ๋Š”๋‹ค.

    JavaScript ์ฝ”๋“œ:

    function coinChange(coins, amount) {
        let dp = new Array(amount + 1).fill(Infinity);
        dp[0] = 0;
        
        for (let coin of coins) {
            for (let j = coin; j <= amount; j++) {
                dp[j] = Math.min(dp[j], dp[j - coin] + 1);
            }
        }
        return dp[amount] === Infinity ? -1 : dp[amount];
    }
    

    ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n × k) (n: ๋™์ „ ๊ฐœ์ˆ˜, k: ๋ชฉํ‘œ ๊ธˆ์•ก)
    ๊ณต๊ฐ„ ๋ณต์žก๋„: O(k)


    2. ๊ฐœ๊ตฌ๋ฆฌ ์ ํ”„ ๋ฌธ์ œ (Frog Jump Problem)

    ๋ฌธ์ œ ์„ค๋ช…

    ๊ฐœ๊ตฌ๋ฆฌ๊ฐ€ ์œ„์น˜ 0์—์„œ k๊นŒ์ง€ ์ด๋™ํ•˜๊ณ  ์‹ถ๋‹ค. ๊ฐœ๊ตฌ๋ฆฌ๋Š” ์ •ํ•ด์ง„ n๊ฐœ์˜ ์ ํ”„ ๊ฑฐ๋ฆฌ ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ ํ”„๋ฅผ ์กฐํ•ฉํ•˜์—ฌ k์— ๋„๋‹ฌํ•˜๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

    JavaScript ์ฝ”๋“œ:

    function frogJump(S, k, q) {
        let dp = new Array(k + 1).fill(0);
        dp[0] = 1;
        
        for (let j = 1; j <= k; j++) {
            for (let s of S) {
                if (s <= j) {
                    dp[j] = (dp[j] + dp[j - s]) % q;
                }
            }
        }
        return dp[k];
    }
    

    ์‹œ๊ฐ„ ๋ณต์žก๋„: O(n × k) (๋ชจ๋“  j์— ๋Œ€ํ•ด n๊ฐœ์˜ ์ ํ”„ ๊ฑฐ๋ฆฌ ํƒ์ƒ‰)
    ๊ณต๊ฐ„ ๋ณต์žก๋„: O(k) (1์ฐจ์› ๋ฐฐ์—ด ์‚ฌ์šฉ)


    3. DP์˜ ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”

    ์œ„ ๋ฌธ์ œ์—์„œ 2์ฐจ์› ๋ฐฐ์—ด์ด ์•„๋‹ˆ๋ผ 1์ฐจ์› ๋ฐฐ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ์กด์˜ 2์ฐจ์› dp[i][j] ๋ฐฐ์—ด ๋Œ€์‹  dp[j]๋งŒ ์œ ์ง€ํ•˜๋ฉด ๋œ๋‹ค.

    JavaScript ์ฝ”๋“œ:

    function optimizedCoinChange(coins, amount) {
        let dp = new Array(amount + 1).fill(Infinity);
        dp[0] = 0;
        
        for (let coin of coins) {
            for (let j = coin; j <= amount; j++) {
                dp[j] = Math.min(dp[j], dp[j - coin] + 1);
            }
        }
        return dp[amount] === Infinity ? -1 : dp[amount];
    }
    

    ์ด๋Ÿฌํ•œ ์ตœ์ ํ™”๋ฅผ ํ†ตํ•ด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ O(k)๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€