在 C++ 中计算属于两个向量的元素数

Calculate Number of Elements that Belong in both Vectors in C++

我们的任务是计算同时属于两个列表的元素数量。 例如,对于列表

vector<int> arr1{5,2,8,9}
vector<int> arr2{3,2,9,5}

答案是 3,因为数字 2、5 和 9 属于两个列表。 我想使这个算法的时间复杂度尽可能低——O(nlogn)。我的目标是对列表进行排序,然后一次遍历它们并找到共同的元素。

这是我目前的情况:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int counter;
    vector<int> arr1{ 5, 2, 8, 9 };
    vector<int> arr2{3, 2, 9, 5};

    sort(arr1.begin(), arr1.end()); // 2, 5, 8, 9
    sort(arr2.begin(), arr2.end()); // 2, 3, 5, 9

    for (int i = 0; i < 4; i++) {
        // insert code here
    }

    cout << counter;

    return 0;
}

如有任何帮助,我们将不胜感激!

答案很简单,因为数组是排序的,你可以在两个数组上有索引 运行,当元素相等时计数,当一个小于另一个时递增。

    while (i < arr1.size() && j < arr2.size()) {
        if (arr1[i] == arr2[j]) {
            ++counter;
            ++i;
            ++j;
        }

        else if (arr1[i] < arr2[i]) {
            ++i;
        }

        else {
            ++j;
        }
    }

请注意,使用集合交集解决此问题的预期时间为 O(n)

您可以像这样使用std::set_intersection

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

int main() {
    std::vector<int> v1{ 1, 2, 3, 4, 5, 6, 7, 8 };
    std::vector<int> v2{ 5, 7, 9, 10 };
    std::sort(v1.begin(), v1.end());
    std::sort(v2.begin(), v2.end());

    std::vector<int> v_intersection;

    std::set_intersection(
        v1.begin(), v1.end(),
        v2.begin(), v2.end(),
        std::back_inserter(v_intersection)
    );

    std::cout << v_intersection.size() << std::endl; // output: 2
}

Michael 向我指出,可以在 O(N) 中完成。您可以使用两个大小为 N 的数组来代替排序。遍历一个向量以标记其中出现的元素,对另一个向量执行相同的操作,然后遍历这两个数组以计算出现在两个数组中的元素。所有单独的步骤都是 O(N),因此总共也是 O(N):

#include <vector>
#include <algorithm>
#include <iostream>
int main() {
    std::vector<int> v1{ 1, 2, 3, 4, 5, 6, 7, 8 };
    std::vector<int> v2{ 5, 7, 9, 10 };

    auto m1 = std::minmax_element(v1.begin(),v1.end());
    auto m2 = std::minmax_element(v2.begin(),v2.end());

    auto min = std::max( *m1.first, *m2.first);  // we only need to consider the max minimum element
    auto max = std::min( *m1.second, *m2.second); // and the min maximum element

    auto get_occurence_vector = [min,max](const std::vector<int>& v) {
        std::vector<bool> result(max-min+1); // max and min included, hence +1
        for (const auto& e : v) {
            int t = e - min;
            if (t >= 0 && t <= max) result[t] = true;
        }
        return result;
    };

    auto occurs_in1 = get_occurence_vector(v1);
    auto occurs_in2 = get_occurence_vector(v2);

    size_t counter = 0;
    for (size_t i = 0;i< occurs_in1.size(); ++i) {
        if (occurs_in1[i] && occurs_in2[i]) {
            std::cout << i + min << "\n";
            ++counter;
        }
    }

    std::cout << "count = " << counter;
}

输出:

5
7
count = 2

基本上是运行-时间复杂度和内存使用之间的权衡。如果向量中值的范围很大,但它们的大小很小,那么排序会更有效,即使复杂度更差(记住复杂度是大的极限 N)。

#include <bits/stdc++.h> 
using namespace std; 
#define MAX 100000 
bitset<MAX> bit1, bit2, bit3; 

// Function to return the count of common elements 
int count_common(int a[], int n, int b[], int m) 
{ 

    // Traverse the first array 
    for (int i = 0; i < n; i++) { 

        // Set 1 at position a[i] 
        bit1.set(a[i]); 
    } 

    // Traverse the second array 
    for (int i = 0; i < m; i++) { 

        // Set 1 at position b[i] 
        bit2.set(b[i]); 
    } 

    // Bitwise AND of both the bitsets 
    bit3 = bit1 & bit2; 

    // Find the count of 1's 
    int count = bit3.count(); 

    return count; 
} 

试试这个方法解决问题。它基本上运行在 O(log min(n,m));