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

C++を使用したK番目のビットセットを使用した範囲内の配列要素の数のクエリ


この記事では、k番目のビットが設定されている特定の範囲に存在する要素の数を見つける問題について説明します。たとえば、-

Input : arr[] = { 4, 5, 7, 2 }
Query 1: L = 2, R = 4, K = 4
Query 2: L = 3, R = 5, K = 1
Output :
   0
   1

ブルートフォースアプローチによってこの問題を解決し、このアプローチがより高い制約に対して機能するかどうかを確認します。そうでない場合は、新しい効率的なアプローチを考えます。

ブルートフォースアプローチ

このアプローチでは、範囲を調べて各要素をチェックし、k番目のビットが設定されているかどうかを確認し、設定されている場合はカウントを増やします。

#include<bits/stdc++.h>
using namespace std;
#define MAX_BITS 32
bool Kset(int n, int k) { // to check if kth bit is set
   if (n & (1 << (k - 1)))
   return true;
   return false;
}
int query(int L, int R, int K, int arr[]) {
   int count = 0; // counter to keep count of number present in the range
   for (int i = L; i <= R; i++) { // traversing the range
      if (Kset(arr[i], K)) {
         count++;
      }
   }
   return count;
}
int main() {
   int arr[] = { 4, 5, 7, 2 }; // given array
   int n = sizeof(arr) / sizeof(arr[0]); // size of our array
   int queries[][3] = { // given L, R and k
      { 2, 4, 4 },
      { 3, 5, 1 }
   };
   int q = sizeof(queries) / sizeof(queries[0]); // number of queries

   for (int i = 0; i < q; i++) {
      int L = queries[i][0] - 1;
      int R = queries[i][1] - 1;
      int K = queries[i][2];

      cout << query(L, R, K, arr) << "\n";
   }
   return 0;
}

出力

0
1

上記のアプローチの時間計算量はO(N * Q)です。ここで、Nは配列のサイズであり、Qは現在与えられているクエリの数です。ご覧のとおり、このアプローチは時間がかかりすぎるため、より高い制約には適していません。そのため、効率的なアプローチのプログラムを作成しようとします。

効率的なアプローチ

このアプローチでは、各インデックスまで使用されるすべてのビットのカウントを保持する2次元プレフィックス合計配列を維持し、O(1)の複雑さで答えを計算できます。

#include<bits/stdc++.h>
using namespace std;
#define bits 32 // number of bits

int P[100000][bits+1];

bool Kset(int n, int k) {
   if (n & (1 << (k - 1)))
      return true;
   return false;
}
void prefixArray(int n, int arr[]) { // building the prefix array
   for (int i = 0; i <= bits; i++) {
      P[0][i] = 0; // setting every bits initial count = 0
   }
   for (int i = 0; i < n; i++) {
      for (int j = 1; j <= bits; j++) {
         bool flag = Kset(arr[i], j);
         if (i) // we add previous count to the latest count(0)
            P[i][j] = P[i - 1][j];
         if (flag) { // if jth bit is set so we increase the count
            P[i][j]++;
         }
      }
   }
}
int query(int L, int R, int K) {
   if (L) // if L not equal to 0 then we return the prefix at R subtracted with prefix at L-1
      return P[R][K] - P[L - 1][K];
   else
      return P[R][K];
}
int main() {
   int arr[] = { 8, 9, 1, 3 }; // given array
   int n = sizeof(arr) / sizeof(arr[0]); // size of given array
   int queries[][3] = {
      { 1, 3, 4 },
      { 2, 4, 1 }
   };
   prefixArray(n, arr); // calling the function to create prefix array
   int q = sizeof(queries) / sizeof(queries[0]); // number of queries

   for (int i = 0; i < q; i++) {
      int L = queries[i][0] - 1;
      int R = queries[i][1] - 1;
      int K = queries[i][2];
      cout << query(L, R, K) << "\n";
   }
   return 0;
}

出力

2
3

O(1)で答えを見つけるのに役立つプレフィックス配列を維持しているため、これにより、時間計算量はO(N)に大幅に削減されます。ここで、Nは指定された配列のサイズです。

上記のコードの説明

このプログラムでは、配列のすべてのインデックスに対して、インデックスまでに使用されるすべてのビットをカウントするプレフィックスカウンターを維持します。すべてのビットのプレフィックスカウントが格納されているので、配列のこのカウントを作成します。したがって、k番目のビットカウントについては、Rインデックスまでのk番目のビットのプレフィックスカウントとL-までのk番目のビットのプレフィックスカウントを減算する必要があります。 1つのインデックスとそれが私たちの答えです。

結論

この記事では、K番目のビットセットを使用して、範囲内の配列要素の数に関するクエリを解決するための問題を解決します。また、この問題のC ++プログラムと、この問題を解決するための完全なアプローチ(通常および効率的)についても学びました。同じプログラムを、C、Java、Python、その他の言語などの他の言語で作成できます。この記事がお役に立てば幸いです。


  1. C++を使用して配列のすべての要素を削除するために必要な操作の最小数。

    問題の説明 整数配列arrが与えられた場合、タスクは、配列のすべての要素を削除するために必要な最小数の操作を出力することです。制限に続いて要素を削除している間- 配列から任意の要素をランダムに選択でき、それで割り切れるすべての要素を配列から削除できます arr [] ={2、4、15、10、8、5、3}の場合、すべての要素を削除するには3つの操作が必要です- 2を選択すると、{2、4、10、8}が削除されます 5を選択すると、{5、15}が削除されます 3を選択すると、{3}が削除されます アルゴリズム 1. Sort the array in ascending or

  2. 配列要素の乗算のためのC++プログラム

    整数要素の配列で与えられ、タスクは配列の要素を乗算して表示することです。 例 Input-: arr[]={1,2,3,4,5,6,7} Output-: 1 x 2 x 3 x 4 x 5 x 6 x 7 = 5040 Input-: arr[]={3, 4,6, 2, 7, 8, 4} Output-: 3 x 4 x 6 x 2 x 7 x 8 x 4 = 32256 以下のプログラムで使用されるアプローチは次のとおりです − 一時変数を初期化して、最終結果を1で格納します ループを0からnまで開始します。nは配列のサイズです 最終結果を得るには、tempの値にarr[i]を掛け続