문제
문제 탐색하기
- 1을 만들 수 있는 최소 연산 횟수 구하기
- 가능한 연산
- 3으로 나누어 떨어지는 경우, 3으로 나누기
- 2으로 나누어 떨어지는 경우, 2으로 나누기
- 1로 빼기
- 경우의 수 구하기
- 2와 3 둘 다 나누어 떨어지는 경우
- 3으로 나누어 떨어지는 경우
- 2로 나누어 떨어지는 경우
- 2와 3 둘 다 나누어 떨어지지 않는 경우
가능한 시간복잡도
입력 범위 ( 1 ≤ N ≤ 10^6)
동적계획법을 사용하여 최악의 경우 시간 복잡도는 O( N )
잘못된 코드
처음에는 이런 식으로 코드를 구현했었는데,
10을 1로 만드는 과정에서 오류가 생긴다.
e.g. 10 → 9 → 3 → 1 (연산 횟수 : 3) 이 되어야하는데 10 → 5 → 4 → 2 → 1 (연산 횟수 : 4) 가 되어버린다.
최소 연산 횟수를 구하는데 사용하는 연산이 정해져있는게 아니라 모든 연산을 통한 후 최소 연산 횟수를 구할 수 있다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int result = cal(n);
System.out.println(result);
}
public static int cal(int n) {
int count = 0;
while(n > 1){
if(n % 6 == 0){ // 2와 3 둘 다 나눠 떨어지는 경우
n = n/3;
} else if(n % 3 == 0){ // 3으로 나눠 떨어지는 경우
n = n/3;
} else if(n % 2 == 0){ // 2로 나눠 떨어지는 경우
n = n/2;
} else { // 2와 3 둘 다 나눠 떨어지지 않는 경우
n = n - 1;
}
count++;
}
return count;
}
}
코드 설계하기
- 최소 연산 횟수를 구할 정수 N을 입력받아 변수에 저장한다.
- 모든 값에 대한 최소 연산 횟수를 저장할 배열 dp 를 선언한다. (Integer 형)
- 경우의 수를 구한다
- 2와 3 둘 다 나누어 떨어지는 경우
- 1 빼기
- 2로 나누기
- 3으로 나누기
- 3으로 나누어 떨어지는 경우
- 3으로 나누기
- 1 빼기
- 2로 나누어 떨어지는 경우
- 2로 나누기
- 1빼기
- 2와 3 둘 다 나누어 떨어지지 않는 경우
- 1빼기
- 2와 3 둘 다 나누어 떨어지는 경우
4. 결과를 출력한다.
풀이 코드
※ Math.min으로 최소 연산 횟수를 구할 때 , n-1인 경우부터 검사하면 시간 초과가 난다. n/3이나 n/2 먼저 호출하면 1까지 빠르게 도달하기 때문에 먼저 호출하도록 하자 !
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static Integer[] dp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
dp = new Integer[n+1];
dp[0] = dp[1] = 0;
System.out.println(cal(n));
}
public static int cal(int n) {
if(dp[n] == null) { // 최소 연산 횟수가 구해지지 않은 경우
if(n % 6 == 0){ // 2와 3 둘 다 나눠 떨어지는 경우
// 3가지 경우의 수 중 최소 연산 횟수를 가져옴 + 연산 횟수 1
dp[n] = Math.min(cal(n-1), Math.min(cal(n/2), cal(n/3))) +1;
} else if(n % 3 == 0){ // 3으로 나눠 떨어지는 경우
dp[n] = Math.min(cal(n/3), cal(n-1)) + 1;
} else if(n % 2 == 0){ // 2로 나눠 떨어지는 경우
dp[n] = Math.min(cal(n/2), cal(n-1)) + 1;
} else { // 2와 3 둘 다 나눠 떨어지지 않는 경우
dp[n] = cal(n-1) + 1;
}
}
return dp[n];
}
}
'코딩테스트' 카테고리의 다른 글
[백준] 17204번 : 죽음의 게임 자바(JAVA) 풀이 (2) | 2024.09.26 |
---|---|
[백준] 10451번 : 순열 싸이클 자바(JAVA) 풀이 (0) | 2024.09.26 |
[백준] 1010번 : 다리 놓기 자바(JAVA) 풀이 (DP) (0) | 2024.09.20 |
[백준] 2775번 : 부녀회장이 될테야 자바(JAVA) 풀이 (0) | 2024.09.20 |
[백준] 2748번 : 피보나치 수 2 자바(JAVA) 풀이 (0) | 2024.09.20 |