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

C++で「pが配列にq回以上出現し、qがp回以上出現する」ペア(p, q)を数える方法

問題の概要

正の整数からなる配列が与えられます。この問題のゴールは、配列arr[]の要素から選んだペア(p, q)のうち、「pが配列内に少なくともq回出現し、かつqが配列内に少なくともp回出現する」という条件を満たすものの総数を求めることです。
具体例を見ながら理解を深めましょう。

入出力例

例1

入力: int arr[] = { 3, 3, 3, 5, 5, 6, 6 }

出力: 条件を満たすペアの数 ― 1

説明: 配列内で条件を満たす有効なペアは(3, 3)のみです。値3は配列内にちょうど3回出現しているためです。有効なペアはこの1つだけなので、答えは1になります。

例2

入力: int arr[] = { 3, 3, 3, 3, 3, 5, 5, 5, 6, 6 }

出力: 条件を満たすペアの数 ― 3

説明: 有効なペアは(3, 3)、(5, 5)、(3, 5)の3つです。値3は配列内に5回、値5は3回出現しています。したがって、有効なペアは3つとなり、答えは3になります。

本プログラムで採用するアプローチ

  • 整数要素からなる配列を入力として受け取り、配列のサイズを計算した上で、以降の処理を行う関数にデータを渡します。
  • pとqの出現回数を格納するための一時変数countを宣言します。
  • vector型の変数vecと、unordered_map型の変数umを作成します。
  • 0から配列のサイズまでのFORループを開始します。
  • ループ内ではum[arr[i]]の値を1増やし、その値が1になった場合(要素が最初に出現した場合)はarr[i]をvecに追加します。
  • 続いて、0からvecのサイズまでの別のFORループを開始します。um[vec[i]] < vec[i]であればcontinueし、等しい場合はcountを1増やします。それ以外の場合もcountを1増やした上で、jをvec[i] + 1からum[vec[i]]まで動かす内側のループを実行します。
  • jのループ内では、um[j] >= vec[i]を満たしていればcountを1増やします。
  • countを返します。
  • 結果を出力します。

アルゴリズムのポイント

この手法では、unordered_mapを使って各値の出現回数を一度の走査で集計し、重複しない値だけをvectorに記録します。その後、各一意な値について「自分自身とのペア」や「出現回数が互いの条件を満たす他の値とのペア」を効率よく数え上げます。すべての要素の組み合わせを素朴に調べる方法に比べ、探索対象を一意な値とその出現回数に限定できるため、はるかに高速に答えを求められます。

コード例

#include <bits/stdc++.h>
using namespace std;
int pair_count(int arr[], int len){
    int count = 0;
    vector<int> vec;
    unordered_map<int, int> um;
    for (int i = 0; i < len; i++){
        um[arr[i]]++;
        if (um[arr[i]] == 1){
            vec.push_back(arr[i]);
        }
    }
    for (int i = 0; i < vec.size(); i++){
        if (um[vec[i]] < vec[i]){
            continue;
        }
        else if (um[vec[i]] == vec[i]){
            count++;;
        }
        else{
            count++;
            for (int j = vec[i] + 1; j <= um[vec[i]]; j++){
                if (um[j] >= vec[i]){
                    count++;
                }
            }
        }
    }
    return count;
}
int main(){
    int arr[] = { 1, 1, 1, 5, 5, 1};
    int size = sizeof(arr) / sizeof(arr[0]);
    cout<<"Count of pairs (p, q) such that p occurs in array at least q times and q occurs at least
p times are: "<<pair_count(arr, size);
    return 0;
}

出力

上記のコードを実行すると、以下の出力が得られます。

Count of pairs (p, q) such that p occurs in array at least q times and q occurs at least p times are: 1
  1. C++でXORが0になる配列内のペアの数を求める方法

    n個の要素を含む配列が与えられたとき、XOR(排他的論理和)の計算結果が0になるペアの数を求めることを考えます。ペア(x, y)のXORが0になるのは、x = y が成り立つ場合、すなわち2つの値が等しいときだけです。これは「同じ数値同士のXORは必ず0になる」というビット演算の基本的な性質によるものです。解法のアプローチこの問題は、次の手順で解くことができます。まず、配列を昇順にソートします。ソート後は同じ値どうしが隣り合って並ぶため、連続する2つの要素を比較し、等しければカウントを1つ増やします。すべての要素が同じ値である場合、末尾側のペアがカウントから漏れる可能性があります。そこで、配列

  2. C++で配列内の a % b = k を満たすすべてのペア(a, b)を検索する方法

    問題の概要配列 A が与えられたとき、その中から a % b = k を満たすすべてのペア(a, b)を見つけることを考えます。たとえば、配列 A = [2, 3, 4, 5, 7]、k = 3 の場合、条件を満たすペアは (7, 4)、(3, 4)、(3, 5)、(3, 7) となります。ここで注意したいのは、(a, b) が順序付きペアであるという点です。つまり (3, 4) と (4, 3) は別々の候補として扱われ、それぞれ剰余演算の結果が k と一致するかどうかが個別に判定されます。解法のアプローチこの問題は、ブルートフォース(総当たり)法によって解くことができます。手順は以下のとお