문제 설명
위와 같은 삼각형의 꼭대기에서 바닥까지 이어지는 경로 중, 거쳐간 숫자의 합이 가장 큰 경우를 찾아보려고 합니다. 아래 칸으로 이동할 때는 대각선 방향으로 한 칸 오른쪽 또는 왼쪽으로만 이동 가능합니다. 예를 들어 3에서는 그 아래칸의 8 또는 1로만 이동이 가능합니다.
삼각형의 정보가 담긴 배열 triangle이 매개변수로 주어질 때, 거쳐간 숫자의 최댓값을 return 하도록 solution 함수를 완성하세요.
제한사항
- 삼각형의 높이는 1 이상 500 이하입니다.
- 삼각형을 이루고 있는 숫자는 0 이상 9,999 이하의 정수입니다.
입출력 예
triangle | result |
[[7], [3, 8], [8, 1, 0], [2, 7, 4, 4], [4, 5, 2, 6, 5]] | 30 |
풀이
처음엔 '깊이우선탐색(DFS)으로 풀어야하나?' 했는데, 만약 높이가 500일 경우 (혹은 그 이상) 경우의 수가 너무 많기도 하고 속도 측면에서 효율적이지 않을 것 같아서 찾아보다가 알게된 게 다이나믹 프로그래밍(DP = Dynamic Programming) 알고리즘입니다.
* DP에 대한 내용은 추후 업로드 할 예정입니다.
DP를 어떤 경우에 활용하느냐? 아주 간단하게 말하자면
1. DFS, BFS를 사용할 수도 있지만 경우의 수가 너무 많을 때
2. 중복이 너무 많을 때
사용한다고 합니다.
해당 문제에서 중복 문제는 무엇을 뜻하냐면, 예를들어 최상위 데이터와 그 아랫줄 데이터인 7+3을 기준으로 봤을 때 거쳐간 숫자의 합의 경우의 수는
1. 7+3+8+2+4
2. 7+3+8+2+5
3. 7+3+8+7+5
4. 7+3+1+7+5
...
입니다.
극히 일부의 경우의 수만 확인했을 뿐인데도 중복이 많은 걸 볼 수 있습니다. 이럴 때 유용하게 사용할 수 있는 알고리즘이 DP입니다.
1. 컴퓨터는 대각선 왼쪽, 오른쪽의 개념이 존재하지 않기 때문에 삼각형을 사각형으로 바꾸어 2차원 배열로 만들었습니다.
0 | 1 | 2 | 3 | 4 | |
0 | 7 | ||||
1 | 3 | 8 | |||
2 | 8 | 1 | 0 | ||
3 | 2 | 7 | 4 | 4 | |
4 | 4 | 5 | 2 | 6 | 5 |
최상위 데이터인 7은 (0,0)이 됩니다.
2.
7은 (0, 0), 3은 (1, 0), 8은 (2, 0), 2는 (3, 0), 4는 (4, 0)
7은 (0, 0), 8은 (1, 1), 0은 (2, 2), 4는 (3, 3), 5는 (4, 4)
규칙이 보이시나요? 먼저 for문으로 dp[i][0]과 dp[i][i]를 구합니다.
3. dp[i][0], dp[i][i]를 구한 다음엔 이 둘을 제외한 dp[i][j]를 중첩 for문으로 구합니다. dp[i][j]는 현재 위치에 도달할 때까지의 최댓값입니다.
문제에서 제시한 데이터 중 dp[i][0], dp[i][i]를 제외한 데이터는 1, 7, 4, 5, 2, 6으로 가장 처음 시작하는 1은 (2, 1)이므로 i는 2부터 시작합니다.
4. 최댓값을 반환할 max를 0으로 초기화합니다.
5. Math.max()를 통하여 dp[dp.length-1][i]를 구하여 거쳐간 숫자의 합이 가장 큰 수인 max를 return합니다.
class Solution1 {
public int solution(int[][] triangle) {
int answer = 0;
// 2차원 배열 초기화
int[][] dp = new int[triangle.length][triangle.length];
// dp[i][0], dp[i][i]
dp[0][0] = triangle[0][0];
for (int i = 1; i < triangle.length; i++) {
dp[i][0] = dp[i - 1][0] + triangle[i][0];
dp[i][i] = dp[i - 1][i - 1] + triangle[i][i];
}
// dp[i][j]
for (int i = 2; i < dp.length; i++) {
for (int j = 1; j < i; j++) {
dp[i][j] = Math.max(dp[i - 1][j - 1], dp[i - 1][j]) + triangle[i][j];
}
}
// 거쳐간 숫자의 합 중 최댓값 구하기
int max = 0;
for (int i = 0; i < dp.length; i++) {
max = Math.max(max, dp[dp.length - 1][i]);
}
return max;
}
}
'programmers' 카테고리의 다른 글
프로그래머스 2단계 : 귤 고르기 (Java 자바) (0) | 2023.08.28 |
---|---|
프로그래머스 3단계 : 네트워크 (Java 자바) (0) | 2023.08.26 |
프로그래머스 2단계 : 최댓값과 최솟값 (Java 자바) (0) | 2023.08.26 |
프로그래머스 0단계 : 공백으로 구분하기 1 (0) | 2023.08.25 |
프로그래머스 0단계 : 수 조작하기 1 (0) | 2023.08.25 |