Programmers Lv3, 등굣길[Java]

junto·2024년 7월 19일
0

programmers

목록 보기
53/66
post-thumbnail

문제

Programmers Lv3, 등굣길

핵심

  • 집에서 학교까지 갈 수 있는 최단 경로의 개수를 구하는 문제이다. 집은 왼쪽 최상단에 위치하며, 학교는 우측 최하단에 위치한다. 오른쪽과 아래 방향으로만 움직일 수 있다.
  • 오른쪽, 아래 방향으로만 움직일 수 있으니, 학교에 도착했다면 해당 거리가 최단 거리임이 보장된다. (어떤 구역을 두 번 거칠 수 없기 때문이다)
  • 문제를 보면 재귀적으로 접근하기 좋다. 상향식과 하향식 접근 모두 알아본다.

1. 하향식 접근(메모이제이션)

  • 큰 문제를 해결하기 위해 작은 문제로 나누는 방식이다. 이미 해결된 작은 문제는 메모이제이션을 통해 반복 계산을 피한다.
  • 먼저 출발지에서 목적지까지의 경로를 찾는다. (큰 문제) 이때, 오른쪽으로 이동하는 경우와 아래쪽으로 이동하는 경우를 재귀적으로 호출한다. (작은 문제) 이때 중복된 계산을 방지하기 위해 memo 배열을 사용할 수 있다.
int goToSchool(int y, int x, int r, int c, int[][] map, int[][] memo) {
	
	if (y >= r || x >= c || map[y][x] == 1)
		return 0;
	
	if (y == r - 1 && x == c - 1)
		return 1;
	
	if (memo[y][x] != -1)
		return memo[y][x];
	
	memo[y][x] = (goToSchool(y + 1, x, r, c, map, memo) + goToSchool(y, x + 1, r, c, map, memo)) % 1_000_000_007;
	
	return memo[y][x];
}

전체 코드

import java.util.*;

class Solution {
    
    public int solution(int m, int n, int[][] puddles) {
        
        int[][] map = new int[n][m];
        int[][] memo = new int[n][m]; 
        
        for (int i = 0; i < puddles.length; ++i) map[puddles[i][1] - 1][puddles[i][0] - 1] = 1;
        
        for (int i = 0; i < n; ++i) Arrays.fill(memo[i], -1);

        return goToSchool(0, 0, n, m, map, memo);
    }
    
    int goToSchool(int y, int x, int r, int c, int[][] map, int[][] memo) {
        
        if (y >= r || x >= c || map[y][x] == 1)
            return 0;
        
        if (y == r - 1 && x == c - 1)
            return 1;
        
        if (memo[y][x] != -1)
            return memo[y][x];
        
        memo[y][x] = (goToSchool(y + 1, x, r, c, map, memo) + goToSchool(y, x + 1, r, c, map, memo)) % 1_000_000_007;
        
        return memo[y][x];
    }
}

2. 상향식 접근

  • 작은 문제를 먼저 해결한 다음, 그 결과를 이용해 점차 큰 문제를 해결하는 방식이다.
  • 먼저 dp[i][j] 점화식을 세운다. 이는 격자에서 (i, j) 위치까지 도달할 수 있는 경로의 수를 뜻하고, 이는 위쪽과 왼쪽에서 오는 경로의 수를 더하여 구할 수 있다.
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
  • 인덱스 범위를 고려한다면 아래와 같이 작성할 수 있다.
dp[0][0] = 1;
for (int i = 0; i < n; ++i) {
	for (int j = 0; j < m; ++j) {
		if (dp[i][j] == -1) {
			dp[i][j] = 0;
		} else {
			if (i > 0) {
				dp[i][j] += dp[i - 1][j];
			}
			if (j > 0) {
				dp[i][j] += dp[i][j - 1];
			}
			dp[i][j] %= 1_000_000_007;
		}
	}
}
return dp[n - 1][m - 1];

전체 코드

import java.util.*;

class Solution {
    
    public int solution(int m, int n, int[][] puddles) {
        
        int[][] dp = new int[n][m];
        
        for (int i = 0; i < puddles.length; ++i) dp[puddles[i][1] - 1][puddles[i][0] - 1] = -1;
        
        dp[0][0] = 1;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (dp[i][j] == -1) {
                    dp[i][j] = 0;
                } else {
                    if (i > 0) {
                        dp[i][j] += dp[i - 1][j];
                    }
                    if (j > 0) {
                        dp[i][j] += dp[i][j - 1];
                    }
                    dp[i][j] %= 1_000_000_007;
                }
            }
        }
        return dp[n - 1][m - 1];
    }
}

시간복잡도

  • O(nm)O(n * m)
profile
꾸준하게

0개의 댓글