C++ 给定一个排序数组和一个参数k,求线性时间内大于或等于k的两个数之和的计数
我试图找到一个和等于k的数组中的所有对。我当前的解决方案需要O(n*log(n))时间(下面的代码片段)。有人能帮我找到更好的解决方案吗,O(n)或O(lgn)(如果存在的话)C++ 给定一个排序数组和一个参数k,求线性时间内大于或等于k的两个数之和的计数,c++,arrays,algorithm,sum,C++,Arrays,Algorithm,Sum,我试图找到一个和等于k的数组中的所有对。我当前的解决方案需要O(n*log(n))时间(下面的代码片段)。有人能帮我找到更好的解决方案吗,O(n)或O(lgn)(如果存在的话) map-mymap; 对它进行迭代器; cin>>n>>k; 对于(int i=0;i>a; if(mymap.find(a)!=mymap.end()) mymap[a]++; 其他的 mymap[a]=1; } for(it=mymap.begin();it!=mymap.end();it++){ int val=i
map-mymap;
对它进行迭代器;
cin>>n>>k;
对于(int i=0;i>a;
if(mymap.find(a)!=mymap.end())
mymap[a]++;
其他的
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);
它->秒=0;
}
}
库特@Drew Dorman-谢谢你的评论
用两个指针遍历数组<代码>左侧
和右侧
假设
left
是小的一面,从left
位置0
开始,然后right
向左移动,直到最后一次a[left]+a[right]>=k
。当达到此目标时,则
total_count+=(a.size-right+1)
然后你向左移动一步,
right
需要(可能)向它移动。重复这个直到他们相遇
当这项工作完成后,让我们假设他们在位置
x
相遇,然后totla_count+=choose(2,a.size-x)
存在一种非常简单的O(n)
方法,使用所谓的“两个指针”或“两个迭代器”方法。关键的思想是在同一个数组上运行两个迭代器(不一定是C++迭代器,索引也会这样),这样如果第一迭代器指向值<代码> x<代码>,那么第二迭代器指向数组中的最大元素,该元素小于<>代码kx。p>
我们将增加第一个迭代器,同时我们还将更改第二个迭代器以维护此属性。注意,随着第一个指针的增加,第二个指针的相应位置只会减少,因此在每次迭代中,我们可以从上一次迭代停止的位置开始;我们永远不需要增加第二个指针。这就是我们实现时间的方法
代码是这样的(没有测试这个,但是想法应该很清楚)
向量a;//给定数组
int r=a.size()-1;
对于(int l=0;l=0)和&(a[r]>=k-a[l]))
r--;
//现在r是a中的最大位置,因此a[r]另一种编写代码可能更简单,但速度稍慢的方法是使用二进制搜索的
O(nlogn)
。对于数组的每个元素a[l]
,您可以找到最大位置r
,这样a[r]就可以完成以下工作:
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" ;
}
void count(int A[],int n)//n是数组中的项数
{int i,j,k,count=0;
cin>>k;
对于(i=0;i
对阵列排序(n个日志n个)
对于(i=1到n)
- 从根本上开始
- 如果[i]+curr\u节点>=k,则向左并匹配=indexof(curr\u节点)e
- 否则,向右走
- 如果curr_node=leaf node,则将[match]之后的所有节点添加到具有[i]的有效对列表中
步骤2还需要O(n logn)。for循环运行n次。在循环中,我们对每个节点执行二进制搜索,即logn步骤。因此,该算法的总体复杂度为O(n logn)。另一种方法是,对于正数,在最佳情况下取O(logn),在最差情况下取O(nlogn):
在数组中查找等于k/2的元素,或者如果它不存在,则查找大于k/2的最小值。我们会对使用此元素和所有较大元素的所有组合感兴趣,因为当p>=k/2和s>=k/2时,p+s>=k。数组已排序,因此可以使用经过一些修改的二进制搜索。此步骤将需要O(日志n)时间
所有小于k/2+元素大于或等于“镜像元素”(根据中位数k/2)的元素也会引起我们的兴趣,因为当p=k/2-t和s>=k/2+t时,p+s>=k。这里我们需要通过小于k/2的元素循环,找到它们的镜像元素(二进制搜索)。如果镜像元素大于最后一个数组,则应停止循环
例如,我们有数组{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,因此计数=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(logn)
对于负数,算法将稍微复杂一点,但也可以用相同的复杂度来求解。可能会有所帮助。在处理之前,您可能会混淆复杂度O(f(n))中的n你可以考虑重命名这个参数。我认为复杂性取决于参数,让我们把它命名为K。当数组被排序时,当你添加<代码>第一个/代码>和<代码>最后< /代码>,结果太大,哪个迭代器要移动,如果它低,该移动哪个?@ Pura-这不是我所说的。ant.我需要总和>=k的对(不仅仅是总和=k)“我试图找到数组中总和等于n的所有对”,这两个对都与标题相矛盾,并且可能在(预期的)线性时间内。如果a[left]+a[right]
然后将向右移动
靠近左侧,仍然会得到比n
@NathanOliver-更小的结果
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
}
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" ;
}