JavaScriptで整数分割のすべてのパターンを求める方法
整数分割(パーティション)とは?
正の整数 n の「分割」とは、n を正の整数の和として表現する方法のことです。ただし、足し合わせる項の順序が異なるだけで実質的に同じになるものは、同一の分割とみなされます。
例えば、4 は以下の5通りの異なる方法で分割できます。
4
3 + 1
2 + 2
2 + 1 + 1
1 + 1 + 1 + 1
今回の課題は、正の整数を唯一の引数として受け取るJavaScript関数を作成することです。この関数は、その整数に対して可能なすべての分割の総数を見つけ出し、返却する必要があります。
アプローチ:動的計画法(DP)
分割の総数を効率よく求めるには、動的計画法(Dynamic Programming)が有効です。2次元のDPテーブルを作成し、各行を「使用できる最大の部分の値」、各列を「対象となる合計値」として扱います。
漸化式のポイントは次のとおりです。
- i > j の場合: i より大きい部分は使えないため、arr[i][j] = arr[i - 1][j] となります。
- それ以外の場合: 「i を含まない分割の数」と「i を少なくとも1つ含む分割の数」の合計を計算します。つまり arr[i][j] = arr[i - 1][j] + arr[i][j - i] です。
最終的な答えは arr[num][num]、つまり num までの値を自由に使って num を作る場合の分割数となります。
コード例
以下がその実装コードです。
const findPartitions = (num = 1) => {
const arr = Array(num + 1).fill(null).map(() => {
return Array(num + 1).fill(null);
});
for (let j = 1; j <= num; j += 1) {
arr[0][j] = 0;
}
for (let i = 0; i <= num; i += 1) {
arr[i][0] = 1;
}
for (let i = 1; i <= num; i += 1) {
for (let j = 1; j <= num; j += 1) {
if (i > j) {
arr[i][j] = arr[i - 1][j];
}
else {
const exclusive = arr[i - 1][j];
const inclusive = arr[i][j - i];
arr[i][j] = exclusive + inclusive;
}
}
}
return arr[num][num];
};
console.log(findPartitions(4));実行結果
コンソールには以下の出力が表示されます。
5
これは冒頭で示したとおり、4 を分割する方法がちょうど5通り存在することを意味しています。この手法の計算量は O(n²) であり、単純な全列挙よりもはるかに高速に分割数を算出できます。
-
JavaScriptで配列内のすべてのピーク(局所最大値)とその位置を検出する方法
データ分析や信号処理の現場では、数値の配列の中から「山」にあたる部分、つまり局所最大値(ピーク)とその位置を特定したい場面がよくあります。本記事では、JavaScriptを使って配列内のすべてのピークと、そのインデックス位置を効率的に検出する方法を解説します。 前提となる例 まず、次のようなJavaScriptの配列を用意します。 const arr = [4, 3, 4, 7, 5, 2, 3, 4, 3, 2, 3, 4]; この配列の各要素をY軸の値としてプロットし、隣り合う要素同士をX軸上で等間隔(単位距離)に配置すると、グラフは以下のようになります。 グラフを見ると分かるように、こ
-
C++で整数の分割(パーティション)をすべて生成するプログラムの実装方法
本記事では、与えられた正の整数 n を正の整数の和として表現する、すべての一意な分割(パーティション)を生成する C++ プログラムを紹介します。例えば 4 という整数は、「4」「3 + 1」「2 + 2」「2 + 1 + 1」「1 + 1 + 1 + 1」のように、複数の組み合わせで表すことができます。このプログラムは、そのような組み合わせを重複なくすべて出力します。 アルゴリズムの考え方 基本的な戦略は「最初に最大の要素だけからなる分割から始め、規則的に次の分割を生成していく」というものです。擬似コードで示すと以下のようになります。 開始 関数 displayAllUniquePart