Динамическое программирование, рекурсия

Комбинация Сумма IV

다이나믹 프로그래밍 과 과 재귀 적 으로 배열 로 있는 있는 문제 로 숫자 로 로 로 있는 문제 을 을 숫자 로 로 을 을 을 을 이다 의 수 를 구하는 문제문제. ▼



다이나믹 프로그래밍 — снизу вверх

다이나믹 프로그래밍은 이전에 계산한 결과값을 저장해두었다가 다음 계산에 이용하는 프로그래밍 방식이다. 고등학교 때 배웠던 식끼리의 관계를 나타내주는 식인 점화식( A(n+1) = A(n)+A(n-1) )을 생각하면 흡사하다고 볼 수 있다.

다이나믹 프로그래밍은 сверху вниз 방식과 снизу вверх 방식으로 나누어 볼 수 있다. 아래는 снизу вверх 방식으로 푼 경우이다. снизу вверх 방식 은 주어진 숫자 배열 로 1 을 만드는 경우 의 수 시작 시작 하여 하여 하여 을 을 까지 하여 하여 하여 이라 을 고 수 까지 구하는 것 것 이라 고 할 수수 N-1, N-2, N-3.

Объяснение кода

  • расческа 배열은 index를 만드는 경우의 수이다. 예를 들어 гребень[3]은 주어진 숫자들로 3을 만드는 경우의 수가 저장된다. 0을 만드는 경우의 수는 한가지이기 때문에 1을 저장하였다.
  • 첫번째 for문은 снизу вверх방식으로 гребень[1] 부터 гребень[цель]까지 구하는 반복문이다.
  • 두번째 for문에서는 гребень[i] += гребень[i — nums[j]] 점화식이 등장한다. 주어진 경우마다 target숫자에서 주어진 배열의 숫자를 뺀 차(i — nums[j])를 구한다. 이 차이를 매우는 경우의 수(comb[i — nums[j]]) 를 구하여 차례로 더해주면 된다. 직접 써보면 이해가 용이하다.
public class Solution {
    public int combinationSum4(int[] nums, int target) {
    
        int[] comb = new int[target + 1]; 
        comb[0] = 1;
    
        for (int i = 1; i < comb.length; i++) {
            for (int j = 0; j < nums.length; j++) {
                if (i - nums[j] >= 0) {
                    comb[i] += comb[i - nums[j]];
                }
            }
        }
        return comb[target];
    }
}

재귀 방식

또 다른 풀이 방법으로는 재귀 방식(рекурсивный)이 있다. return 1을 해주는 조건을 지정하는 것이 포인트이다.

public int combinationSum4(int[] nums, int target) {
    if (target == 0) {
        return 1;
    }
    
    int res = 0;
    for (int i = 0; i < nums.length; i++) {
        if (target >= nums[i]) {
            res += combinationSum4(nums, target - nums[i]);
        }
    }
    return res;
}

마무리

  • 점화식을 이용해야한다는 느낌은 있었는데 점화식과 for문이 결합된 형태는 처음 접해보아 신툠선.
for (int j = 0; j < nums.length; j++) {
      if (i - nums[j] >= 0) {
         comb[i] += comb[i - nums[j]];
      }
}