【问题标题】:Calculate Number of Elements that Belong in both Vectors in C++在 C++ 中计算属于两个向量的元素数
【发布时间】:2020-07-28 22:51:08
【问题描述】:

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

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;
}

任何帮助将不胜感激!

【问题讨论】:

  • 您需要什么帮助?你知道笔和纸是怎么做的吗?
  • @idclev463035818 好吧,是的,我正在努力使这个基本算法在 O(nlogn) 时间内尽可能高效
  • 如果你有重复的A={5,5,5,2,2,8,9,9}, B={3,3,2,2,2,2,9,5}怎么办?答案还应该是 3 吗?
  • @0x499602D2 感谢您要求澄清。在这种情况下,您不会计算重复项,因此答案仍然是 3,因为数字 2、5、9 属于两个列表,无论它们是否出现
  • 向量的取值范围是否受限?

标签: c++ vector stl time-complexity stdvector


【解决方案1】:

您可以使用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
}

【讨论】:

    【解决方案2】:

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

        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)

    【讨论】:

    • 不,无论排序如何,构建一个集合都是O(n)
    • 也许我只是无知,您能否在O(n) 中提供参考?
    • 好吧,找到了,你需要一个大小为n的数组,然后就可以了
    【解决方案3】:
    #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));

    【讨论】:

    • O(log min(n,m)); 你忘了n 吗?我没有研究每一个细节,但这充其量是O( n log n),因为你的部分是线性的
    【解决方案4】:

    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 的限制)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      • 1970-01-01
      • 2011-06-12
      • 2019-04-19
      相关资源
      最近更新 更多