Study note/Coding test

DP - Dynamic Programming

공대 아로마 2024. 4. 12. 17:26

기술면접을 위해 기초 CS에 대한 복습중이다.
공부한 내용 중 요점이나 나중에 기억해야할 부분을 정리해보려고 한다.
내가 아는 부분은 생략되어 있을 수 있고, 혹여나 틀린 부분이 있을 수도 있으니 이 글을 보고 '다른 사람'이 공부하기에는 도움이 되지 않을 수 있으니 주의!

다이나믹 프로그래밍

  • 피보나치 수열처럼 점화식 풀 때 사용한다.
  • 이미 계산한 것은 다시 계산을 하지 않게끔 하는 것이 목적이다.
  • 탑다운과 보텀업 방식이 있다.
  • 보텀업: DP 테이블을 만들어서 하는 방식.
      // 첫 번째 피보나치 수와 두 번째 피보나치 수는 1
      d[1] = 1;
      d[2] = 1;
      int n = 50; // 50번째 피보나치 수를 계산
      // 피보나치 함수(Fibonacci Function) 반복문으로 구현
      for (int i = 3; i <= n; i++) {
          d[i] = d[i - 1] + d[i - 2];
      }
      cout << d[n] << '\n';
  • 탑다운: 한 번 계산된 결과는 메모이제이션(Memoization)하는 방식.
      long long fibo(int x) {
          // 종료 조건(1 혹은 2일 때 1을 반환)
          if (x == 1 || x == 2) {
              return 1;
          }
          // 이미 계산한 적 있는 문제라면 그대로 반환
          if (d[x] != 0) {
              return d[x];
          }
          // 아직 계산하지 않은 문제라면 점화식에 따라서 피보나치 결과 반환
          d[x] = fibo(x - 1) + fibo(x - 2);
          return d[x];
      }

다이나믹 프로그래밍 VS 분할 정복

  • 공통점: 큰 문제를 작은 문제로 나눌 수 있다. 작은 문제를 모아 큰 문제를 풀 수 있다.
  • 차이점: DP는 부분 문제가 중복되지만, 분할 정복은 동일 문제가 반복되지 않는다.

DP 문제에 접근하는 방법

  • 문제를 풀 때 가장 먼저 그리디, 구현, 완전 탐색 등으로 생각해보고, 너무 많은 시간 복잡도가 소요된다고 생각이 들면 다이나믹을 고려해본다.
  • 부분 문제가 반복적이고, 작은 문제에서 구한 답이 큰 문제에 그대로 사용될 수 있다면 DP일 가능성이 높다.
  • DP의 2가지 조건: 최적 부분 구조, 중복되는 부분 문제
  • DP 테이블에는 구하고자 하는 값을 인덱스마다 차례로 넣는다.
  • 점화식 만들기: $x-1$이나 $x-k$ 이런 식으로 어떤 특정 위치에서 직전 계산을 이용할 수 있도록 구현해야 한다.

LIS (Longest Increasing Subsequence)

  • 특정 위치 v[i]를 마지막 값으로 하는 부분 수열에 대해서 LIS를 구한다.
    // 오름차순 조건을 만족한다면
    if(v[j] < v[i])
      // 현재까지의 LIS 값과 v[j] 위치에서의 LIS에 v[i]까지 더한 값,
      // 즉, d[j] + 1과 비교한다.
      d[i] = max(d[i],d[j] +1)

※ Vector 문법

// 크기는 3, 모든 값은 10000으로 초기화
vector<int> v(3, 10000);

// 거꾸로 뒤집기
reverse(v.begin(), v.end());

참고한 사이트

'Study note > Coding test' 카테고리의 다른 글

순열 - 재귀함수 (C++)  (0) 2024.04.12
Hash 문법 정리 (C++)  (0) 2024.04.12
Binary Search  (0) 2024.04.12
그래프 탐색 알고리즘: DFS/BFS  (0) 2024.04.12
그리디 & 구현  (0) 2024.04.12