让我们在大小为B[1:K]
的数组K
上定义一个操作,即计算子数组B[2:K]
中小于B[1]
的元素数。
现在我有一个大小为A[1:N]
的数组N
,我的目标是对所有大小为K
的连续子数组执行上述操作。
实施例
A = [4, 3, 6, 2, 1] and K = 3
3
大小为3
个连续的子阵列。
B = [4, 3, 6]
count = 1
[(3 < 4)]
B = [3, 6, 2]
count = 1
[(2 < 3)]
B = [6, 2, 1]
count = 2
[(2 < 6), (1 < 6)]
蛮力方法的时间复杂度为O((N-K+1)*K)
,因为对大小为K
的连续子阵列执行上述操作为O(K)
。
如果可以设计数据结构,我可以在Nlog(M)
中高效地完成
它具有以下属性
log(M)
log(M)
X
log(M)
的元素数量
醇>
我是C++
用户,我不认为有任何数据结构可以满足所有上述要求。还有其他改进方法吗?请帮忙。
答案 0 :(得分:1)
您可能希望使用set来计算小于k的元素的附加操作。这可以实现为二进制搜索树(经典集合实现),在每个节点中具有附加统计(基本上是树中节点的大小)。
此处有更多详情:https://stackoverflow.com/a/15321444/1391392 这里有一些实现:https://sourceforge.net/projects/orderstatistics/
其他选项可能看起来更直接,就是使用跳过列表。 https://en.wikipedia.org/wiki/Skip_list
答案 1 :(得分:0)
这有帮助吗?
#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
int bit[100005]={0};
// using BIT since numbers can repeat and set won't work
void update(int idx, int val, int n){
while(idx < n){
bit[idx] += val;
idx += (idx & -idx);
}
}
int get(int idx){
int ret = 0;
while(idx > 0){
ret += bit[idx];
idx -= (idx & -idx);
}
return ret;
}
int main() {
int n, a[100005] = {0}, i, ans=0, k, maxx = -1;
scanf("%d%d", &n, &k);
for(i=0; i<n; i++){
scanf("%d", &a[i]);
if(maxx < a[i]){
maxx = a[i];
}
}
maxx++;
for(i=0;i<n;i++){
a[i] = maxx - a[i];
}
// now the problem becomes the opposite of what it initially was
// now a[i] would contribute to ans if we can find an element a[j] where a[j] < a[i] and (i-j)<=k
for(i=0;i<n;i++){
if(i-k>=0){
// remove i-k'th element from the BIT since it doesn't contribute
update(a[i-k], -1, maxx);
}
if(i >= k-1){
// add how a[i] is gonna contribute to the final answer, it would be the number of elements less than a[i]
ans += get(a[i]);
}
// add a[i] to the BIT
update(a[i], 1, maxx);
}
printf("%d\n", ans);
return 0;
}