contents

๐Ÿ“˜ ์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(DP) ๊ฐ€์ด๋“œ

๋‹ค์Œ์€ DP์˜ ํ•ต์‹ฌ ๊ฐœ๋…, ์œ ํ˜•, ๊ตฌํ˜„ ์ „๋žต, ๊ทธ๋ฆฌ๊ณ  Java ์Šคํƒ€์ผ์˜ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ ์ƒ์„ธ ์„ค๋ช…์ž…๋‹ˆ๋‹ค.


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

๋™์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Dynamic Programming)์€ ํฐ ๋ฌธ์ œ๋ฅผ ์ž‘์€ ํ•˜์œ„ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜์—ฌ ์žฌ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ถˆํ•„์š”ํ•œ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ํ”ผํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.


2. DP ํŒจํ„ด & ์˜ˆ์ œ

a. ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด

์žฌ๊ท€ (๋น„ํšจ์œจ์ )

int fib(int n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}

DP (Top-down + ๋ฉ”๋ชจ์ด์ œ์ด์…˜)

int[] memo = new int[n+1];
int fib(int n) {
    if (n <= 1) return n;
    if (memo[n] != 0) return memo[n];
    return memo[n] = fib(n - 1) + fib(n - 2);
}

DP (Bottom-up)

int fib(int n) {
    if (n <= 1) return n;
    int[] dp = new int[n+1];
    dp[0] = 0; dp[1] = 1;
    for (int i = 2; i <= n; i++)
        dp[i] = dp[i-1] + dp[i-2];
    return dp[n];
}

b. 0/1 ๋ฐฐ๋‚ญ ๋ฌธ์ œ (Knapsack)

๋ฌธ์ œ:
๊ฐ๊ธฐ ๋‹ค๋ฅธ ๋ฌด๊ฒŒ์™€ ๊ฐ€์น˜๋ฅผ ๊ฐ€์ง„ n๊ฐœ์˜ ์•„์ดํ…œ์ด ์ฃผ์–ด์งˆ ๋•Œ, ๋ฐฐ๋‚ญ ๋ฌด๊ฒŒ ์ œํ•œ W ์•ˆ์—์„œ ์ตœ๋Œ€ ๊ฐ€์น˜๋ฅผ ๊ตฌํ•˜์„ธ์š”.

int knapsackDP(int[] w, int[] v, int W) {
    int n = w.length;
    int[][] dp = new int[n+1][W+1];
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= W; j++) {
            if (w[i-1] <= j)
                dp[i][j] = Math.max(dp[i-1][j],
                                    dp[i-1][j-w[i-1]] + v[i-1]);
            else
                dp[i][j] = dp[i-1][j];
        }
    }
    return dp[n][W];
}

c. ์ตœ์žฅ ์ฆ๊ฐ€ ๋ถ€๋ถ„์ˆ˜์—ด (LIS)

int lengthOfLIS(int[] nums) {
    int n = nums.length, max = 1;
    int[] dp = new int[n];
    Arrays.fill(dp, 1);
    for (int i = 1; i < n; i++)
        for (int j = 0; j < i; j++)
            if (nums[i] > nums[j])
                dp[i] = Math.max(dp[i], dp[j] + 1);
    for (int val : dp) max = Math.max(max, val);
    return max;
}

d. ํŽธ์ง‘ ๊ฑฐ๋ฆฌ(Edit Distance)

int editDistance(String a, String b) {
    int[][] dp = new int[a.length()+1][b.length()+1];
    for (int i = 0; i <= a.length(); i++)
        for (int j = 0; j <= b.length(); j++) {
            if (i == 0) dp[i][j] = j;
            else if (j == 0) dp[i][j] = i;
            else if (a.charAt(i-1) == b.charAt(j-1))
                dp[i][j] = dp[i-1][j-1];
            else
                dp[i][j] = 1 + Math.min(dp[i-1][j-1],
                               Math.min(dp[i-1][j], dp[i][j-1]));
        }
    return dp[a.length()][b.length()];
}

e. ๋™์ „ ๊ตํ™˜ (Coin Change)

int coinChange(int[] coins, int amount) {
    int[] dp = new int[amount+1];
    Arrays.fill(dp, amount+1);
    dp[0] = 0;
    for (int coin : coins)
        for (int i = coin; i <= amount; i++)
            dp[i] = Math.min(dp[i], dp[i-coin] + 1);
    return dp[amount] > amount ? -1 : dp[amount];
}

3. DP ๋ฌธ์ œ ์œ ํ˜•๋ณ„ ๋ถ„๋ฅ˜

์œ ํ˜• ์˜ˆ์‹œ ๋ฌธ์ œ ์ƒํƒœ ์ •์˜ ์˜ˆ
๋ถ€๋ถ„์ˆ˜์—ด/๋ถ€๋ถ„๋ฐฐ์—ด LIS, LCS dp[i], dp[i][j]
๊ฒฉ์ž/2D ๊ฒฝ๋กœ Unique Paths, ์ตœ์†Œ ๊ฒฝ๋กœ ํ•ฉ dp[i][j]
๋ถ€๋ถ„์ง‘ํ•ฉ/Partition Knapsack, Target Sum dp[i][j] ๊ฐ€๋Šฅ ์—ฌ๋ถ€
๋ฌธ์ž์—ด ๋ณ€ํ™˜ Edit Distance, Palindrome dp[i][j]
๊ฒฝ์šฐ์˜ ์ˆ˜ ๊ณ„์‚ฐ Coin Change, Climb Stairs dp[i] = ๊ฒฝ์šฐ์˜ ์ˆ˜

4. DP ๊ตฌํ˜„ ๋‹จ๊ณ„

  1. ์ƒํƒœ ์ •์˜ (State)
    • ๋ฌธ์ œ๋ฅผ ๋” ์ž‘์€ ํ•˜์œ„ ๋ฌธ์ œ๋กœ ์ •์˜
  2. ๊ธฐ์ € ์กฐ๊ฑด (Base case)
    • ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์˜ ํ•ด๋ฅผ ๋ฏธ๋ฆฌ ์ •์˜
  3. ์ ํ™”์‹ (Recurrence Relation)
    • ํฐ ๋ฌธ์ œ๋ฅผ ์ž‘์€ ๋ฌธ์ œ์˜ ํ•ด๋กœ๋ถ€ํ„ฐ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•
  4. ๊ณ„์‚ฐ ์ˆœ์„œ (Iteration Order)
    • Bottom-up ๋˜๋Š” Top-down
  5. ์ตœ์ ํ™” (Optimization)
    • ๊ณต๊ฐ„ ์ตœ์ ํ™”(1D ๋ฐฐ์—ด), ๋ถˆํ•„์š”ํ•œ ๊ณ„์‚ฐ ์ค„์ด๊ธฐ

5. ์‹ค์ „ ํŒ


6. ๊ณ ๊ธ‰ ๊ฐœ๋…


7. ์š”์•ฝ ํ…Œ์ด๋ธ”

๋ฌธ์ œ ์œ ํ˜• DP ์ƒํƒœ ์˜ˆ ์ ํ™”์‹ ์˜ˆ์‹œ
ํ”ผ๋ณด๋‚˜์น˜ dp[n] dp[n-1] + dp[n-2]
LIS dp[i] max(dp[j]+1) if a[i]>a[j]
Edit Distance dp[i][j] dp[i-1][j-1], dp[i][j-1]โ€ฆ
Coin Change dp[amount] min(dp[amount-coin]+1)
Knapsack dp[i][w] max(์ด์ „๊ฐ’, ์ด์ „+value)

references