C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で解く「組み合わせの総和IV」――メモ化再帰による実装方法

問題概要

すべての要素が正の整数で、かつ重複のない整数配列が与えられたとします。このとき、要素を足し合わせて正の整数 target になる組み合わせが何通りあるかを求めるのが本問題です。順序が異なる並びは、別々の組み合わせとして数える点に注意してください。

例えば、配列が [1, 2, 3]、ターゲットが 4 の場合、考えられる組み合わせは [[1,1,1,1], [1,1,2], [1,2,1], [2,1,1], [1,3], [3,1], [2,2]] の7通りとなるため、出力は 7 になります。

解法のアプローチ

この問題は、メモ化再帰(トップダウン型の動的計画法)を用いることで効率的に解けます。手順は以下の通りです。

  • 再帰関数 solve() を用意します。引数として、配列・ターゲット・動的計画法(メモ化)用の配列を受け取ります。
  • target が 0 の場合は 1 を返します(組み合わせが1通り完成したことを意味します)。
  • dp[target] が -1 以外(計算済み)であれば、その値を返します。
  • ans を 0 で初期化します。
  • i を 0 から nums の要素数までループします。
    • target >= nums[i] の場合、ans := ans + solve(nums, target - nums[i], dp) を実行します。
  • dp[target] に ans を格納します。
  • ans を返します。

一度計算したターゲット値の結果を dp 配列にキャッシュすることで、同じ状態の再計算を避けられます。時間計算量は O(target × n)(n は配列の要素数)、空間計算量は O(target) となります。

C++での実装例

理解を深めるために、以下の実装例を見てみましょう。

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector <int> dp(target + 1, -1);
        return helper(nums, target, dp);
    }
    int helper(vector <int>& nums, int target, vector <int>& dp){
        if(target == 0)return 1;
        if(dp[target] != -1)return dp[target];
        int ans = 0;
        for(int i = 0; i < nums.size(); i++){
            if(target >= nums[i]){
                ans += helper(nums, target - nums[i], dp);
            }
        }
        return dp[target] = ans;
    }
};
main(){
    Solution ob;
    vector<int> v = {1,2,3};
    cout << ob.combinationSum4(v, 4);
}

入力

[1,2,3]
4

出力

7
  1. C++でアリコート和(Aliquot Sum)を計算する方法

    本記事では、アリコート和(Aliquot Sum)とは何かを解説します。アリコート和とは、ある数 n の約数のうち、n 自身を除いたすべての約数の総和のことです。例えば、数値が 20 の場合、その約数は (1, 2, 4, 5, 10) となるため、アリコート和は 22 になります。興味深い点として、アリコート和がその数自身と等しくなる場合、その数は「完全数」と呼ばれます。例えば 6 の場合、約数は (1, 2, 3) であり、アリコート和は 1 + 2 + 3 = 6 となるため、6 は完全数です。それでは、以下のアルゴリズムを使ってアリコート和を求める方法を見ていきましょう。アルゴリズムg

  2. Pythonで組み合わせの総和(Combination Sum)を求める再帰アルゴリズムの解説

    組み合わせの総和問題とは 候補となる数値のリスト(すべての要素が一意)と目標値が与えられたとき、候補の数値を足し合わせて目標値と一致する、すべての一意な組み合わせを求めるのが「組み合わせの総和」問題です。このとき、同じ数値は何度でも繰り返し使用できる点が特徴です。 たとえば、要素が [2,3,6,7] で目標値が 7 の場合、考えられる出力は [[7], [2,2,3]] となります。 解法のアプローチ この問題は再帰処理によって解きます。再帰関数 solve() は、結果を保存する配列(res)、重複チェック用の辞書(map)、目標値(target)、そして一意な要素のリスト(elemen