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

JavaScriptで数値Nを2の累乗のチャンクに分割する方法【パーツ数・サイズ制限付き】

はじめに

本記事では、与えられた数値を特定のルールに従って分割(パーティション)するJavaScript関数の実装方法を解説します。分割の条件は次のとおりです。

  • チャンク(パーツ)の総数は2の累乗でなければなりません。

  • 各チャンクに含まれる要素数も2の累乗でなければなりません(サイズの上限は32。つまり 1, 2, 4, 8, 16, 32 のいずれか)。

具体例で理解する

たとえば 8 は、1つのバケットにそのまままとめることができます。

[8]

9 の場合は次のように分割できます。

[8, 1]

これは有効な分割です。どちらの数値も2の累乗であり、配列のサイズが2(これも2の累乗)であるためです。

次に 11 を試してみましょう。

[8, 2, 1]

一見すると合計は11ですが、この分割は無効です。配列のサイズが3であり、3は2の累乗ではないからです。

[4, 4, 2, 1]

こちらは有効です。要素数が4であり、4は2の累乗だからです。

コード例

この問題を解くコードは次のようになります。

function permuteCombinations(n, maximum){
   const maxPowerOf2 = 1 << maximum;
   const m = ~~(n / maxPowerOf2);
   const A = new Array(maximum + 1).fill(0);
   A[maximum] = m;
   let num = n − m * maxPowerOf2;
   let p = 0;
   let bitCount = 0;
   while (num){
      if (num & 1){
         bitCount += 1;
         A[p] = 1;
      }
      num >>= 1;
      p += 1;
   }
   const min = m + bitCount;
   let target = 1;
   while (target < min)
   target *= 2;
   if (target > n)
   return −1;
   if (target == min)
   return A.map((c, p) => [1 << Number(p), c]);
   if (target == n)
   return [n];
   target = target − min;
   let i = m ? maximum : p;
   while (target && i > 0){
      if (!A[i]){
         i −= 1;
         continue;
      }
      const max = Math.min(target, A[i]);
      A[i] −= max;
      A[i−1] += 2*max;
      target −= max;
      i −= 1;
   }
   return target ? −1 : A.map((c, p) => [1 << Number(p), c]);
};
console.log(permuteCombinations(11, 5));

出力結果

コンソールには次のように出力されます。

[ [ 1, 1 ], [ 2, 1 ], [ 4, 2 ], [ 8, 0 ], [ 16, 0 ], [ 32, 0 ] ]

出力の読み方

この出力は「[チャンクのサイズ, 個数]」のペアを表しています。つまり、サイズ1のチャンクが1個、サイズ2のチャンクが1個、サイズ4のチャンクが2個という意味です。合計すると 1×1 + 2×1 + 4×2 = 11 となり、チャンクの総数は 1 + 1 + 2 = 4 で、2の累乗という条件も満たしています。

このように、まず最大サイズ(2のmaximum乗)でできるだけ多くのチャンクを作り、残りをビット演算で分解したうえで、必要に応じて大きなチャンクを2つずつの小さなチャンクへ分割していくことで、条件を満たす組み合わせを効率的に求められます。条件を満たす分割が存在しない場合は −1 が返されます。

  1. JavaScriptで幅とアスペクト比(幅:高さ)から高さを計算する方法

    本記事では、画面の幅とアスペクト比(幅:高さ)を入力として受け取り、それに基づいて画面の高さを算出するJavaScript関数の実装方法を解説します。 問題 次の要件を満たすJavaScript関数を作成する必要があります。 第1引数として画面の幅を受け取る 第2引数としてアスペクト比(w:h の形式の文字列)を受け取る これら2つの入力値をもとに、画面の高さを計算して返す コード例 以下がその実装コードです。 {     const [w, h] = ratio     .split(:)  &n

  2. JavaScriptで整数を素数のべき乗の積として表現する方法

    本記事では、正の整数を受け取り、その数を素数のべき乗の積として表す文字列を返すJavaScript関数の作成方法を解説します。 問題の概要 任意の正の整数 n を引数として受け取り、次の形式の文字列を返す関数を実装します。 n = "(p1**n1)(p2**n2)...(pk**nk)" ここで p1〜pk は素因数となる素数、n1〜nk はそれぞれに対応する指数です。「a**b」は「a の b 乗」を意味します。 例 例として 86240 を渡した場合、この数は次のように素因数分解できます。 86240 = 25 × 5 × 72 × 11 したがって、期待される出