簡體   English   中英

查找范圍內大於x的數字

[英]Finding a number greater than x in a range

我有一個問題,經過一些修改后縮小為“在[l,r]范圍內找到數字大於x的最小索引”

例如:假設數組A = {1, 2, 3, 6, 9, 8, 4, 3, 7, 6, 2} 1,2,3,6,9,8,4,3,7,6,2 A = {1, 2, 3, 6, 9, 8, 4, 3, 7, 6, 2}

並且查詢是“ 在范圍[2,6]中查找數組A中元素的最小索引,其大於或等於5

上述查詢的答案為4(該指數的值為6)(指數為1)

有多個查詢,數組沒有排序(考慮輸入已經在內存中)

是否存在可以在O(logN)中進行查詢的算法,其中N為否。 數組A中的元素

在構建一個占用O(N)空間的數據結構之后,實際上有很多方法可以在O(log N)時間內支持查詢。

容易理解答案

  • 使用A的元素作為葉子創建二叉樹,按索引排序。
  • 在每個內部節點中,記錄其子樹中葉子的最大值
  • 您需要能夠在給定索引的情況下找到節點的路徑。 如有必要,記錄每個內部節點中第一個葉子的索引。 沒有這個,你可以通過建造一個方便形狀的樹來逃脫。
  • 現在,要找到值> = X的最小索引> = L:
    • 在樹中找到A [L]的路徑
    • 如果A [L] <X,則向上移動樹,直到找到包含值> = X的右叔叔
    • 沿着叔叔樹走下去,找到值> = X的第一片葉子。 在降序時,如果左子的葉子> = X(檢查存儲的最大值),則向左移動。 否則就走吧。

超高效的答案

為了使上述算法真正有效,您可以將樹編碼為數組,就像我們對堆進行編碼一樣。 在此表示中(使用基於1的索引),您有一個包含N-1個內部節點的最大值的數組,后面依次是N個葉子。 調用該數組H 那么H[i]的孩子是H[i*2]H[i*2+1] H[i]的父母是H[i>>1]

在偽代碼中,使用基於1的索引,我們給出:

A[] = input array, N = input array size

我們像這樣建立H:

H = new array with size N*2-1, indexed from 1 to N*2-1
for (int i=1; i<=N; ++i)
    H[i+N-1]=A[i];
for (int i=N-1; i>0; --i)
    H[i] = max(H[2*i],H[2*i+1]);

請注意,我們在父母之前創建子項,以便當我們需要獲取其值的最大值時,子項就在那里。

現在,查詢功能:

//get the index of the first element with val >= minval, index >= minindex, and index <= maxindex
//returns -1 if there is no such element

firstAtLeast(minval, minindex, maxindex)

    if (maxindex < minindex)
        return -1;

    node = minindex+N-1; //find minindex in the tree

    //go up and right until we find a subtree that has a value >= minval

    while(H[node] < minval)

        //if we are a right child of our parent, go up until
        //we have a right sibling
        while( (node&1) == 1 ) //node is odd
            node = node>>1;    //same as floor(node/2);
            if (node <= 1)
                //we went up to the root
                //there is no such element
                return -1;

        //now node is a left child.  try its right sibling        
        ++node;

    //We found a subtree.  get the first valid leaf

    while(node < N) //while it's an internal node
       node = 2*node; //left child of the node
       if (H[node] < minval)
           ++node;  //left child not valid - move to right child

    //Found leaf.  get index in A[i] and check against maxindex

    index = node-(N-1);
    return (index <= maxindex ? index : -1);

這滿足了O(log N)時間內查詢的要求。 當你知道沒有一個小於maxindex的答案時,提前退出會很好(而且不是太困難),但這會使偽代碼變得不那么清晰,所以我會把它maxindex練習

O(logN)接縫是不可能的。 您至少需要讀取輸入,直到第一個元素更大(這可能是最后一個元素或根本沒有)。 因此,在最壞的情況下,您需要讀取整個輸入,這意味着O(N)

只有在輸入的某些額外結構(如排序)比將算法改進為O(logN)時才能進行改進。

如果存在多個查詢,則仍需要O(logN) 您可以一次檢查多個查詢,也可以緩存相同查詢再次出現的結果。

如果可能元素的數量很小(比如K)並且可以很容易地枚舉,對於N個元素的數組,您可以使用計數排序按N + K順序對它們進行排序 然后,您可以對查詢使用二進制搜索,這將是訂單日志N.注意,計數排序還需要訂單K內存,因此僅在相對較少數量的離散鍵正在運行時才有用。 如果您有Q查詢,則復雜度為O((N + K)+ Q(log(N))

如果您有大量查詢,並且數據量適中,那么您可以通過O(N)額外存儲來提高查詢速度。

創建元組的aray (a[i], i) (即數組中的值,該值的索引),按第一個(以及在沖突的情況下,第二個)按升序排序。 然后,使用二進制搜索找到您的起點。 如果索引超出范圍,請繼續遍歷排序列表,直到找到符合您感興趣范圍的索引。

我懷疑這個算法是O(N),最壞的情況,所以我想有可能做得更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM