简体   繁体   English

创建一个函数,用于检查数组是否具有两个相反的元素,但复杂度低于n ^ 2。 (C ++)

[英]Create a function that checks whether an array has two opposite elements or not for less than n^2 complexity. (C++)

Create a function that checks whether an array has two opposite elements or not for less than n^2 complexity. 创建一个函数,用于检查数组是否具有两个相反的元素,但复杂度低于n ^ 2。 Let's work with numbers. 让我们使用数字。

Obviously the easiest way would be: 显然最简单的方法是:

bool opposite(int* arr, int n) // n - array length
{
 for(int i = 0; i < n; ++i)
  { 
    for(int j = 0; j < n; ++j)
     {
       if(arr[i] == - arr[j])
          return true;
     }
  }

  return false;
}

I would like to ask if any of you guys can think of an algorithm that has a complexity less than n^2. 我想问一下你们是否有人能想到一个复杂度小于n ^ 2的算法。 My first idea was the following: 1) sort array ( algorithm with worst case complexity: n.log(n) ) 2) create two new arrays, filled with negative and positive numbers from the original array ( so far we've got -> n.log(n) + n + n = n.log(n)) 3) ... compare somehow the two new arrays to determine if they have opposite numbers 我的第一个想法如下:1)排序数组(具有最差情况复杂度的算法:n.log(n))2)创建两个新数组,填充原始数组中的负数和正数(到目前为止我们已经得到 - > n.log(n)+ n + n = n.log(n))3)...比较两个新数组以确定它们是否具有相反的数字

I'm not pretty sure my ideas are correct, but I'm opened to suggestions. 我不太确定我的想法是否正确,但我对建议持开放态度。

I would use an std::unordered_set and check to see if the opposite of the number already exist in the set. 我会使用std::unordered_set并检查该数字中是否存在相反的数字。 if not insert it into the set and check the next element. 如果没有将其插入集合并检查下一个元素。

std::vector<int> foo = {-10,12,13,14,10,-20,5,6,7,20,30,1,2,3,4,9,-30};
std::unordered_set<int> res;
for (auto e : foo)
{
    if(res.count(-e) > 0)
        std::cout << -e << " already exist\n";
    else 
        res.insert(e);
}

Output: 输出:

opposite of 10 alrready exist
opposite of 20 alrready exist
opposite of -30 alrready exist

Live Example 实例

An important alternative solution is as follows. 一个重要的替代解决方案如下。 Sort the array. 对数组进行排序。 Create two pointers, one initially pointing to the front (smallest), one initially pointing to the back (largest). 创建两个指针,一个最初指向前面(最小),一个最初指向后面(最大)。 If the sum of the two pointed-to elements is zero, you're done. 如果两个指向元素的总和为零,那么就完成了。 If it is larger than zero, then decrement the back pointer. 如果它大于零,则递减后退指针。 If it is smaller than zero, then increment the front pointer. 如果它小于零,则递增前指针。 Continue until the two pointers meet. 继续,直到两个指针相遇。

This solution is often the one people are looking for; 这个解决方案通常是人们正在寻找的; often they'll explicitly rule out hash tables and trees by saying you only have O(1) extra space. 通常他们会通过说你只有O(1)额外空间来明确排除哈希表和树。

Let's see that you can simply add all of elements to the unordered_set and when you are adding x check if you are in this set -x . 让我们看看你可以简单地将所有元素添加到unordered_set ,当你添加x检查时,如果你在这个set -x The complexity of this solution is O(n). 该解决方案的复杂性是O(n)。 (as @Hurkyl said, thanks) (正如@Hurkyl所说,谢谢)

UPDATE : Second idea is: Sort the elements and then for all of the elements check (using binary search algorithm) if the opposite element exists. 更新 :第二个想法是:对元素进行排序,然后对所有元素进行检查(使用二进制搜索算法),如果相反的元素存在。

You can do this in O(n log n) with a Red Black tree. 您可以使用红黑树在O(n log n)中执行此操作。

t := empty tree
for each e in A[1..n]
    if (-e) is in t:
        return true
    insert e into t
return false

In C++, you wouldn't implement a Red Black tree for this purpose however. 但是,在C ++中,您不会为此目的实现Red Black树。 You'd use std::set , because it guarantees O(log n) search and insertion. 你使用std::set ,因为它保证了O(log n)的搜索和插入。

std::set<int> s;
for (auto e : A) {
    if (s.count(-e) > 0) {
        return true;
    }
    s.insert(e);
}
return false;

As Hurkyl mentioned, you could do better by just using std::unordered_set , which is a hashtable. 正如Hurkyl所提到的,你可以通过使用std::unordered_set来做得更好,这是一个哈希表。 This gives you O(1) search and insertion in the average case, but O(n) for both operations in the worst case. 这样可以在平均情况下进行O(1)搜索和插入,但在最坏的情况下进行O(n)操作。 The total complexity of the solution in the average case would be O(n). 平均情况下解决方案的总复杂度为O(n)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM