在每次插入后找到最后K个元素的最小值,其中K未固定:
例如Given Array 10 2 4 1 3
Query K = 3
ans : 1 (minimum of 4 1 3)
Insertion : 5
10 2 4 1 3 5
Query K =2
ans = 3
Insertion 2
10 2 4 1 3 5 2
Query K =4
ans 1
对于每个查询,是否有一种有效的方法可以在少于O(n)的时间内处理此类查询?
答案 0 :(得分:3)
我假设您在开头就知道应该插入的最大元素数,以便您可以相应地为它们分配空间。
然后一个最小段树应该工作。最初,分段树中的所有元素都包含" INT_MAX"值。
随着新元素的到来,相应的叶子(及其祖先)会更新。选择用于更新的叶子是根据流中元素的位置。
然后可以轻松执行间隔查询。
插入和查询操作都需要O(log n)
次。
答案 1 :(得分:1)
有一种方法可以使用数组和二进制搜索来解决这个问题。
首先,我们处理数组,并保持索引数组的值越来越大。
因此,对于数组10 2 4 1 3
,在队列中我们有1 3
每次我们将一个元素插入数组时,我们会尝试删除数组末尾的所有元素,这些元素大于当前元素,因此当我们插入5 - >数组变为1 3 5
,然后插入2 - >队列成为1 2
。
因此,要查询范围K中的最小元素,我们需要找到数组中最接近队列开头的元素,并且索引在最后一个K元素的范围内,这很容易使用二分搜索完成。
因此,所有插入的总时间将是每个插入的O(n)或平均O(1),并且对于每个查询是O(log n)。
伪代码
int[] q;
int numberOfElement = 0;
for(int i = 0; i < n; i++){
while(numberOfElement > 0 && data[q[numberOfElement - 1]] >= data[i]){
numberOfElement--;
}
q[numberOfElement++] = i;
}
//Insert at index i:
while(numberOfElement > 0 && data[q[numberOfElement - 1]] >= data[i]){
numberOfElement--;
}
q[numberOfElement++] = i;
//Query for range K
int start = 0;
int end = numberOfElement - 1;
int result = 0;
while(start <= end){
int mid = (start + end) >> 1;
if(q[mid] >= totalElement - K){
result = mid;
end = mid - 1;
} else{
start = mid + 1;
}
}
答案 2 :(得分:0)
如果您知道要预先插入的元素数量,那么您可以使用 @Abhishek Bansal
回答(细分树)。否则,您可以使用BST(二叉搜索树),例如 Treap 。您使用数组中的元素索引作为键,节点的值是数组中的值。因此,插入元素将需要O(log(n))
并且查询的复杂性相同(查询是从last_index-k + 1到last_index的最大范围查询,两者都是键)。
以下是treap的代码(用于maxrange查询),但minrange是同一个想法:https://ideone.com/M9rnbg
答案 3 :(得分:0)
创建并维护最大尺寸k
的 min-heap tree 。在每次插入之前,您需要delete kth
树中最后min-heap
插入的值,并在插入后最小化树。
根节点值(在插入之后)始终在最后插入的k
元素中存储最小值。
对于每个查询:
删除费用:O(log k)
广告费用:O(log k)
查找最低费用:O(1)
因此,整体时间复杂度为O(log k)
(小于O(n)
)。