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

C++で2つのBSTから合計が指定値xと等しいペアを数える方法


2つの二分探索木(BST)と整数値 x が与えられます。この記事の目的は、BST_1 から1つのノード、BST_2 からもう1つのノードを選んだペアのうち、両ノードの値の合計が x に一致するものの個数を求めることです。具体的には、BST_1 のノードと BST_2 のノードのデータ部分を加算し、その合計が x と等しければカウントを1つ増やしていきます。

具体例で確認してみましょう。

入力

C++で2つのBSTから合計が指定値xと等しいペアを数える方法

出力 − 合計が指定値 x に等しい2つのBSTからのペアの数 − 1

説明 − 該当するペアは (8, 6) です。

入力

C++で2つのBSTから合計が指定値xと等しいペアを数える方法

出力 − 合計が指定値 x に等しい2つのBSTからのペアの数 − 2

説明 − 該当するペアは (5, 15) と (4, 16) です。

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

このアプローチでは、スタックを利用した反復的な中順走査(インオーダー走査)によって2つのBSTを同時に走査します。BST_1 は最小ノードから最大ノードへ向かう昇順の中順走査で辿り、BST_2 は逆順(降順)の中順走査で辿ります。そして、両方のBSTにおける現在ノードの値の合計を評価します。合計が x と等しければカウントを増やし、合計が x より大きければ BST_2 側を次に小さいノード(先行ノード)へ進め、合計が x より小さければ BST_1 側を次に大きいノード(後続ノード)へ進めます。これは、ソート済み配列から合計が特定の値になるペアを探す「双方向ポインタ」手法を、2つのBSTに応用したものと言えます。

  • 整数型のデータ部分と、子ノードを指す left・right ポインタを持つ2つの木 BST_1 と BST_2 を用意します。
  • 関数 insert_node(int data) は、指定したデータを持つ新しいノードを作成し、そのポインタを返します。
  • insert_node() を使って両方のBSTを構築し、BST_sum_x(Tree* BST_1, Tree* BST_2, int x) に渡します。
  • 関数 BST_sum_x(...) は、両方の木の根ノードと目標値 x を受け取り、データ部分の合計が x になるノードのペアの個数を返します。
  • 合計が x となるペアの数を数えるため、カウントの初期値を 0 とします。
  • 反復的な中順走査のために、Tree* 型の変数 stack_top_1 と stack_top_2 を宣言します。
  • 2つのスタック stack_1 と stack_2 を作成します。
  • 外側の while ループを開始します。
  • while ループで BST_1 の最左端(最小値)ノードまで進み、経路上のすべてのノードを stack_1 にプッシュします。
  • while ループで BST_2 の最右端(最大値)ノードまで進み、経路上のすべてのノードを stack_2 にプッシュします。
  • どちらかのスタックが空になったら、外側の while ループを抜けます。
  • 両スタックのトップにあるノードのデータ部分を加算し、temp に格納します。
  • temp(合計)== x の場合は count をインクリメントし、pop 操作で stack_1 と stack_2 の両方からトップ要素を削除します。その後、BST_1 = stack_top_1->right、BST_2 = stack_top_2->left と設定します(それぞれ BST_1 の次の後続ノード、BST_2 の次の先行ノード)。
  • temp < x の場合は stack_1 のみからトップを削除し、BST_1 の次の後続ノードへ移動します。
  • temp > x の場合は stack_2 のみからトップを削除し、BST_2 の次の先行ノードへ移動します。
  • 外側の while ループが終了した時点で、count には合計が x となるペアの総数が格納されています。
  • count を結果として返します。

なお、この手法の時間計算量は O(n1 + n2)、空間計算量は O(h1 + h2) となります(n1・n2 は各木のノード数、h1・h2 は各木の高さ)。すべてのノードの組み合わせを総当たりで調べる O(n1 × n2) の素朴な方法に比べ、大幅に効率的である点が大きな利点です。

#include <bits/stdc++.h>
using namespace std;
struct Tree{
    int data;
    Tree* left, *right;
};
Tree* insert_node(int data){
    Tree* newNode = (Tree*)malloc(sizeof(Tree));
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
}
int BST_sum_x(Tree* BST_1, Tree* BST_2, int x){
    int count = 0;
    Tree* stack_top_1, *stack_top_2;
    stack<Tree*> stack_1, stack_2;
    if (BST_1 == NULL || BST_2 == NULL){
        return 0;
    }
    while (1){
        while (BST_1 != NULL){
            stack_1.push(BST_1);
            BST_1 = BST_1->left;
        }
        while (BST_2 != NULL){
            stack_2.push(BST_2);
            BST_2 = BST_2->right;
        }
        if (stack_1.empty() || stack_2.empty()){
            break;
        }
        stack_top_1 = stack_1.top();
        stack_top_2 = stack_2.top();
        int temp = stack_top_1->data + stack_top_2->data;
        if (temp == x){
            count++;
            stack_1.pop();
            stack_2.pop();
            BST_1 = stack_top_1->right;
            BST_2 = stack_top_2->left;
        }
        else if (temp < x){
            stack_1.pop();
            BST_1 = stack_top_1->right;
        }
        else{
            stack_2.pop();
            BST_2 = stack_top_2->left;
        }
    }
    return count;
}
int main(){
    //BST 1
    Tree* BST_1 = insert_node(15);
    BST_1->left = insert_node(10);
    BST_1->right = insert_node(8);
    BST_1->left->left = insert_node(12);
    BST_1->left->right = insert_node(24);
    BST_1->right->left = insert_node(16);
    //BST 2
    Tree* BST_2 = insert_node(20);
    BST_2->left = insert_node(16);
    BST_2->right = insert_node(4);
    BST_2->left->left = insert_node(18);
    BST_2->left->right = insert_node(28);
    BST_2->right->left = insert_node(22);
    int x = 28;
    cout<<"Count of pairs from two BSTs whose sum is equal to a given value x ar: "<<BST_sum_x(BST_1, BST_2, x);
    return 0;
}

出力

上記のコードを実行すると、次の出力が生成されます −

Count of pairs from two BSTs whose sum is equal to a given value x ar: 1
  1. 【C++】ソート済み双方向連結リスト内で合計が指定値xと等しくなるトリプレットを数える方法

    問題の概要 整数値を格納したソート済みの双方向連結リスト(doubly linked list)が与えられます。この問題の目的は、リストから3つのノードを選んだとき、そのデータ値の合計が指定された値 x と一致するようなトリプレット(3つ組)が何通り存在するかを数えることです。 たとえば、連結リストが 3 → 4 → 1 → 2 で x = 6 の場合、条件を満たすのは (3, 1, 2) だけなので、答えは 1 となります。 入力例 1 linked list: [ 3 − 4 − 13 − 5 − 10 − 10 − 0 ] x = 20 出力 Count of triplets i

  2. ソート済み双方向連結リストで積が指定値xと等しくなるトリプルの個数を数えるC++プログラム

    問題の概要 整数値を格納したソート済みの双方向連結リスト(doubly linked list)が与えられます。この課題の目標は、3つのノードのデータの積が指定された値xと等しくなるようなトリプル(三つ組)の個数を求めることです。 例えば、入力リンクリストが「3→4→1→2」でxが6の場合、積が6になるトリプルは(3, 1, 2)の1つだけなので、カウントは1となります。 入力例と出力例 例1 入力: linked list: [ 200→4→16→5→10→10→2 ]、x = 200 出力: 積が指定値xと等しくなるトリプルの個数: 3 説明: 該当するトリプルは以下の3つです。 (4