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

【C++】同じセットビット数を持つ数値を加算して得られる最大合計の求め方

問題文

N個の数値からなる配列が与えられたとき、同じ数のセットビット(2進数表現で「1」になっているビット)を持つ数値同士をグループ化して加算し、その中で最大となる合計値を求めるのが課題です。

入力配列が {2, 5, 8, 9, 10, 7} の場合、出力は 24 になります。まず各数値のセットビット数を確認してみましょう。

  • 2 のセットビット数は 1(10進数: 2 → 2進数: 10)

  • 5 のセットビット数は 2(2進数: 101)

  • 8 のセットビット数は 1(2進数: 1000)

  • 9 のセットビット数は 2(2進数: 1001)

  • 10 のセットビット数は 2(2進数: 1010)

  • 7 のセットビット数は 3(2進数: 111)

このうち、セットビット数が 2 である数値は 5、9、10 の3つです。これらを加算すると 5 + 9 + 10 = 24 となり、これが求める最大合計です。

アルゴリズム

  • 配列を走査し、各要素のセットビット数をカウントします。

  • 32ビット整数を想定し、セットビット数は最大32通りであることから、サイズ32の合計用配列を初期化します。

  • 配列を反復処理し、各要素を「その要素のセットビット数」に対応するインデックスの位置に加算していきます。

  • 最後に合計用配列を走査し、最大値を見つけて返します。

実装例

#include <bits/stdc++.h>
using namespace std;
int bitCount(int n){
    int count = 0;
    while (n) {
        count++;
        n = n & (n - 1);
    }
    return count;
}
int maxSum(int arr[], int n){
    int bits[n];
    for (int i = 0; i < n; i++) {
        bits[i] = bitCount(arr[i]);
    }
    int sum[32] = { 0 };
    for (int i = 0; i < n; i++) {
        sum[bits[i]] += arr[i];
    }
    int maximum = 0;
    for (int i = 0; i < 32; i++) {
        maximum = max(sum[i], maximum);
    }
    return maximum;
}
int main(){
    int arr[] = {2, 5, 8, 9, 10, 7};
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Maximum sum = " << maxSum(arr, n) << endl;
    return 0;
}

出力

上記のプログラムをコンパイルして実行すると、以下の出力が得られます。

Maximum sum = 24

コードのポイントと計算量

bitCount 関数では、Brian Kernighan のアルゴリズムn & (n - 1) を繰り返す手法)を採用しています。この方法では、1回の演算ごとに最下位のセットビットが1つ消えるため、セットビットの数だけの反復で効率よくカウントできます。

  • 時間計算量: O(N × B)。N は配列の要素数、B は各数値のビット長です。

  • 空間計算量: O(1)。サイズ32の補助配列のみを使用するため、実質的に定数領域で動作します。

  1. C++を使って行列内で合計が最大の列を見つける方法

    ここでは、サイズ M × N の行列が与えられたときに、要素の合計が最大となる列を見つける方法を解説します。この問題では、難しいアルゴリズムを用いる必要はありません。行列を列方向に走査して各列の合計値を計算し、その合計が最大であれば、合計値と該当する列のインデックスを出力するというシンプルなアプローチで十分です。アルゴリズムの手順処理の流れは以下の通りです。1. 最大合計値を格納する変数 maxSum を INT_MIN で初期化し、列のインデックスを格納する index を -1 に設定します。2. 各列(0 ~ N-1)について、colSum 関数を使ってその列の要素の合計を計算します。3

  2. C++で2つの数値の交互ビットを組み合わせて新しい数値を生成する方法

    この問題では、2つの数値の交互のビットを使って新しい数値を生成します。具体的には、2番目の数値から1番目のビットを、1番目の数値から2番目のビットを、再び2番目の数値から3番目のビットを、1番目の数値から4番目のビットを…というように、LSB(最下位ビット)側から順に交互にビットを取り出していきます。 まず、例を使って問題をより深く理解しましょう。 入力 : n = 6, m = 10 出力 : 2 説明 : 6 のビット表現 = 0110 10 のビット表現 = 1010 0 1 1 0 (n = 6) ^ ^ ← この位置のビットを採用 1 0 1 0 (m =