triangle (꼭대기부터 바닥까지 이어짐).[i+1][j]) 또는 대각선 오른쪽([i+1][j+1])으로만 이동 가능하다.이 문제는 전형적인 동적계획법(Dynamic Programming) 문제다.
위에서부터 아래로 내려가며 합을 구하되, 특정 위치 (i, j)에 도달했을 때의 최댓값은 "바로 위층에서 올 수 있는 두 경로 중 더 큰 값을 선택"하는 것으로 결정된다.
dp[i][j]: (0, 0)에서 시작해 (i, j) 위치까지 도달했을 때 얻을 수 있는 최대 합.현재 위치 (i, j)로 내려올 수 있는 경우는 위층(i-1)의 두 곳이다.
(i-1, j-1)(i-1, j)따라서 기본 점화식은 다음과 같다.
하지만 단순히 위 점화식만 쓰면 인덱스 에러(ArrayIndexOutOfBounds)가 발생한다. 삼각형의 양쪽 끝은 내려올 수 있는 경로가 하나뿐이기 때문이다.
j == 0): 바로 위층의 0번 인덱스에서만 올 수 있다.dp[i][j] = triangle[i][j] + dp[i-1][j]j == len-1): 바로 위층의 마지막 인덱스에서만 올 수 있다.dp[i][j] = triangle[i][j] + dp[i-1][j-1]import java.util.*;
// dp[i][j] = triangle[i][j] + Math.max(dp[i-1][j-1], dp[i-1][j]);
public class Solution {
public static int solution(int[][] triangle){
int answer = 0;
int n = triangle.length; // size
int[][] dp = new int[n][];
for(int i=0; i<n; i++) {
dp[i] = new int[i+1];
}
dp[0][0] = triangle[0][0];
for(int i=1; i<n; i++) {
for(int j=0; j<triangle[i].length; j++) {
if(j == 0) {
dp[i][j] = triangle[i][j] + dp[i-1][j];
}
else if(j == triangle[i].length - 1) {
dp[i][j] = triangle[i][j] + dp[i-1][j-1];
}
else {
dp[i][j] = triangle[i][j] + Math.max(dp[i-1][j-1], dp[i-1][j]);
}
}
}
for(int maxVal : dp[n-1]) {
answer = Math.max(answer, maxVal);
}
return answer;
}
}
어제까지만 해도 실버 난이도의 DP 문제도 접근조차 못 해서 우울했는데, '계단 오르기'를 통해 "현재 값을 구하기 위해 과거의 값을 참조한다"는 DP의 본질을 이해하고 나니 Lv.3 문제도 두렵지 않게 되었다. 역시 기본기가 중요하다.
자바에서 2차원 배열의 열 크기를 행마다 다르게 설정할 수 있다는 점을 활용했다.
new int[n][]으로 선언하고, 반복문을 돌며 new int[i+1]로 할당하니 삼각형 구조에 딱 맞는 배열이 만들어져서 인덱스 관리하기도 편하고 메모리도 절약할 수 있었다.
DP 문제는 점화식도 중요하지만, j-1 같은 인덱스를 참조할 때 범위 밖으로 나가는 것을 방지하는 것이 핵심이다. 이번에는 if (j==0), else if (j==last), else로 명확하게 분기 처리를 해서 한 번에 정답 처리를 받을 수 있었다.
Tags: #Java #Algorithm #Programmers #DP #DynamicProgramming