문제를 해결할 때 작은 문제부터 해결하여서 큰 문제를 해결하는 문제 풀이 방식이다.
백트래킹과 같이 특정 알고리즘이 아니고 문제 해결 방식이다. Dynamic Programming(DP)라고도 부른다.
메모리를 많이 사용하지만 빠른 성능을 보이므로 효율이 좋을 때가 있다.
동적계획법은 Memoization(하향식 접근법)과 Tabulation(상향식 접근법)으로 두 방법론이 있다.
작은 문제들의 결과를 메모리에 저장하고 이를 필요할 때 꺼내쓰는 방법이다.
기존 백트래킹 방식으로 문제를 해결하다보면 중복되는 탐색이 존재할 수 있다.
이럴 경우 해당 탐색 결과를 메모리에 저장해두고 중복이 발생하면 꺼내쓰는 방식이 Memoization이다.
f(n) = f(n-1) + f(n-2)이라는 규칙을 가지는 수열이다.필요한 값들을 미리 계산해두는 방식으로 문제를 해결하는 방식이다.
Memoization이 필요할 때 계산하는 것이라면 Tabulation은 미리 계산해둔다는 차이점이 있다.
코딩 테스트에서는 대부분 Memoization이 많이 사용된다.
동적 계획법 유형은 딱 봐서는 동적계획법을 사용해야 하는지 파악하기가 어렵다.
따라서 문제가 다음과 같은 형태를 띄는지 확인해본다.
하지만 활용가능하다고 반드시 동적계획법으로 해결할 수 있는 것은 아니다.
동적계획법은 메모리를 많이 사용하므로 시간복잡도가 초과되어 문제 해결이 불가능할 수도 있다.
이럴 경우에는 백트래킹으로 통해서 해결해야 하나 자주 출제되는 문제 유형은 아니다.
동적 계획법 강의를 들었기에 작은 문제부터 찾아보았으나 1시간 동안 감을 잡지 못하였다.
괜히 레벨 4가 아니었다.
해설의 아이디어를 참고하여 문자열을 잘라 단어 퍼즐 유무를 확인하면서 기존에 구한 최소 갯수를 갱신하는 방식으로 해결하였다.
function solution(strs, t) {
// dp 배열 생성 t의 길이 + 1만큼
const dp = Array(t.length + 1).fill(0);
// 일반 배열보다 Set 객체가 탐색이 빠르다.
const sets = new Set(strs);
// 문자열 길이만큼 탐색
for (let i=1; i<t.length + 1; i++) {
// 최솟값을 구하므로 기본값은 무한이다.
dp[i] = Infinity;
// 문자열을 단어 조각만큼 자르면서 탐색한다.
for (let j=1; j < Math.min(i + 1, 6); j++) {
const start = i - j;
const end = i;
// 단어 조각이 이미 있으면
if (sets.has(t.slice(start, end))) {
// 이전 조합 + 1과 현재값 비교 후 최솟값 대입
dp[i] = Math.min(dp[i], dp[i-j] + 1);
}
}
}
return dp[dp.length - 1] === Infinity ? -1 : dp[dp.length - 1];
}
😅 해당 내용은 공부하면서 정리한 글입니다. 틀린 부분이나 오해하고 있는 부분이 있다면 피드백 부탁드립니다.