[英]Given a sorted array and a parameter k, find the count of sum of two numbers greater than or equal to k in linear time
我试图在总和等于 k 的数组中找到所有对。 我当前的解决方案需要 O(n*log(n)) 时间(下面的代码片段)。任何人都可以帮助我找到更好的解决方案,O(n) 或 O(lgn) 可能是(如果存在)
map<int,int> mymap;
map<int,int>::iterator it;
cin>>n>>k;
for( int i = 0 ; i < n ; i++ ){
cin>>a;
if( mymap.find(a) != mymap.end() )
mymap[a]++;
else
mymap[a] = 1;
}
for( it = mymap.begin() ; it != mymap.end() ; it++ ){
int val = it->first;
if( mymap.find(k-val) != mymap.end() ){
cnt += min( it->second, mymap.find(k-val)->second );
it->second = 0;
}
}
cout<<cnt;
另一种在最好情况下采用 O(log n) 而在最坏情况下采用 O(nlog n) 正数的方法可以通过以下方式完成:
例如,我们有数组 {1,3,5,8,11} 和 k = 10,所以在第一步我们将有 k/2 = 5 和对 {5,7}, {8,11}, {8 , 11}。 这些对的计数将通过公式 l * (l - 1)/2 计算,其中 l = 元素计数 >= k/2。 在我们的例子中 l = 3,所以 count = 3*2/2=3。
在 3 数的第二步中,镜像元素将为 7(5-2=3 和 5+2=7),因此对 {3, 8} 和 {3, 11} 会感兴趣。 对于 1 号镜像将是 9(5-4=1 和 5+4=9),所以 {1, 11} 是我们要寻找的。
因此,如果 k/2 < 第一个数组元素,则该算法将是 O(log n)。
对于否定,算法会稍微复杂一点,但也可以用相同的复杂度解决。
存在使用所谓的“两个指针”或“两个迭代器”方法的相当简单的O(n)
方法。 关键思想是在同一个数组上运行两个迭代器(不一定是 C++ 迭代器,索引也可以),这样如果第一个迭代器指向值x
,那么第二个迭代器指向数组中小于那么的最大元素kx
.
我们将增加第一个迭代器,同时我们还将更改第二个迭代器以保持此属性。 注意,随着第一个指针的增加,第二个指针对应的位置只会减少,所以每次迭代都可以从上次迭代停止的位置开始; 我们永远不需要增加第二个指针。 这就是我们如何实现O(n)
时间。
代码是这样的(这个没测试过,但是思路应该很清楚)
vector<int> a; // the given array
int r = a.size() - 1;
for (int l=0; l<a.size(); l++) {
while ((r >= 0) && (a[r] >= k - a[l]))
r--;
// now r is the maximal position in a so that a[r] < k - a[l]
// so all elements right to r form a needed pair with a[l]
ans += a.size() - r - 1; // this is how many pairs we have starting at l
}
另一种编码可能更简单但速度稍慢的方法是使用二进制搜索的O(n log n)
。 对于数组的每个元素a[l]
,您可以找到最大位置r
,使得a[r]<ka[l]
使用二分搜索(这与第一个算法中的r
相同)。
@Drew Dormann - 感谢您的评论。
用两个指针遍历数组。 left
和right
。
假设left
是小边,从位置0
left
开始,然后right
移动,直到最后一次a[left]+a[right] >= k
。
当达到这一点时,则total_count += (a.size - right + 1)
。
然后你left
移动一步, right
需要(可能)朝它移动。 重复这个直到他们相遇。
完成后,假设他们在位置x
相遇,然后totla_count += choose(2, a.size - x)
。
步骤 2 也需要 O(n log n)。 for 循环运行 n 次。 在循环中,我们对每个节点执行二分搜索,即记录 n 步。 因此,算法的整体复杂度为 O (n log n)。
这应该做的工作:
void count(int A[], int n) //n being the number of terms in array
{ int i, j, k, count = 0;
cin>>k;
for(i = 0; i<n; i++)
for(j = 0; j<n; j++)
if(A[i] + A[j] >= k)
count++ ;
cout<<"There are "<<count<<" such numbers" ;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.