자연수 x를 y로 변환하려고 합니다. 사용할 수 있는 연산은 다음과 같습니다.
x | y | n | result |
---|---|---|---|
10 | 40 | 5 | 2 |
10 | 40 | 30 | 1 |
2 | 5 | 4 | -1 |
입출력 예 #1
x에 2를 2번 곱하면 40이 되고 이때가 최소 횟수입니다.
입출력 예 #2
x에 n인 30을 1번 더하면 40이 되고 이때가 최소 횟수입니다.
입출력 예 #3
x를 y로 변환할 수 없기 때문에 -1을 return합니다.
1. 리스트를 사용하여 구현
class Solution {
private static final int MAX = Integer.MAX_VALUE;
public static int solution(int x, int y, int n) {
int answer = 0;
int[] dp = new int[y + 1];
for (int i = x + 1; i < y + 1; i++) {
int a = MAX, b = MAX, c = MAX, d;
if (isDivided(i, 2) && aboveX(x, i / 2)) a = dp[i / 2];
if (isDivided(i, 3) && aboveX(x, i / 3)) b = dp[i / 3];
if (aboveX(x, i - n)) c = dp[i - n];
// 숫자 i를 만들기 위한 최소 방법을 찾음
d = Math.min(a, b);
d = Math.min(d, c);
// 만들 수 있으면 d+1 저장
// 만들 수 없다면 MAX 저장
dp[i] = (d < MAX) ? d + 1 : MAX;
}
// y를 만들 수 없다면 -1 반환
answer = (dp[y] < MAX) ? dp[y] : -1;
return answer;
}
// x 보다 작은 위치의 값을 비교하지 않게 함
private static boolean aboveX(int x, int num) {
return (num >= x);
}
// (i / 2), (i / 3)의 연산 결과가 자연수인지 확인함
private static boolean isDivided(int num, int divide) {
return (num / divide > 0 && num % divide == 0);
}
}
오랜만에 풀어보는 dp 문제..
총 3가지의 연산이 가능하다
푸는 방법은 다음과 같다.
말로는 이해하기 어려우니, 그림으로 설명해보자
x=10, y=25, n=5인 경우를 생각해보자.
우선 y의 값까지 배열을 만든다.
x는 10이고, 11부터 25까지 1씩 증가시키며 해당 숫자를 만들 수 있는 최소 방법을 찾아간다.
우선, 10을 만드는 방법은 자기 자신이므로 0이다.
11을 만드는 방법은 다음과 같다.
11을 만들 수 있는 방법은 6에서 5를 더하는 방법 뿐인데 x보다 작은 값이기 때문에 제외시킨다.
11~14까지 동일한 이유로 만들 수 없다.
만들 수 없는 수는 MAX로 표시한다.
15를 만들 수 있는 방법은 다음과 같다.
15는 10+5로 만들 수 있다.
따라서 한 가지의 방법으로 만들 수 있으므로 그 최소값을 저장한다.
16~19도 만들 수 없다.
20을 만들 수 있는 방법은 (i / 2)와 (i - n)이다.
(i / 2)의 값은 10이고, 배열 10에 저장된 값인 0에서 1을 더한 값인 1이 20을 만들 수 있는 최소이다.
(i - n)의 값은 15이고, 배열 15에 저장된 값인 1에서 1을 더한 값인 2가 20을 만들 수 있는 최소이다.
두 경우를 비교했을 때 (i / 2)인 10에서 만드는 것이 최소이므로 1이 최소가 된다.
21~24는 만들 수 없고
25는 (i - n)에 의해 2가 된다.