在每次插入后找到最后K个元素的最小值,其中K在小于O(n)时间内不固定

时间:2016-09-06 07:53:41

标签: algorithm data-structures

在每次插入后找到最后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)的时间内处理此类查询?

4 个答案:

答案 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))。