簡體   English   中英

查找數組中給定范圍內的最小數字

[英]Find smallest number in given range in an array

嗨,我有一個大小為N的數組。數組值將始終僅具有1、2、3個整數值。 現在,我需要找到給定范圍的數組索引之間的最小數字。 因此,例如對於array = 2 1 3 1 2 3 1 3 3 2. 2. [2-4] = 1,[4-5] = 2,[7-8] = 3等范圍的最小值。

下面是我的代碼:

static void Main(String[] args) {
    string[] width_temp = Console.ReadLine().Split(' ');
    int[] width = Array.ConvertAll(width_temp,Int32.Parse);  // Main Array              
    string[] tokens_i = Console.ReadLine().Split(' ');
    int i = Convert.ToInt32(tokens_i[0]);
    int j = Convert.ToInt32(tokens_i[1]);
    int vehicle = width[i];
    for (int beg = i+1; beg <= j; beg++) {
        if (vehicle > width[beg]) {
            vehicle = width[beg];
        }
    }
    Console.WriteLine("{0}", vehicle);
}

上面的代碼工作正常。 但我擔心的是效率。 在上面,我只是采用一組數組范圍,但是實際上將有n個范圍,並且我將必須為每個范圍返回最低的范圍。 現在的問題是,如果存在[0-N]之類的范圍,N是數組大小,那么我最終將所有項目進行比較以得到最低的結果。 所以我想知道是否有辦法優化代碼以提高效率???

我認為這是一個RMQ(范圍最小查詢),有幾種實現方式可能適合您的情況。

這是一個很好的TopCoder教程 ,其中有很多內容,我推薦其中兩個:

使用教程中的表示法,將<P, T>定義為<Preprocess Complexity, Query Complexity> ,有兩種著名且通用的可處理RMQ的實現/數據結構: 平方根數組段樹

段樹是著名的但難以實現,它可以解決<O(n), O(lg n)> RMQ,其復雜度比平方根數組( <O(n), O(sqrt(n))>


平方根數組( <O(n), O(sqrt(n))>

請注意,這不是該技術的正式名稱,也不是任何數據結構,實際上,我自從了解以來就不知道該技術是否有任何正式命名...但是在這里,我們開始

圖片來自TopCoder教程

對於查詢時間,絕對不是解決RMQ的最佳方法,但是它具有一個優點:易於實現! (與細分樹相比...)

這是它如何工作的高級概念:

N為數組的長度,我們將數組分為sqrt(N)組,每個組包含sqrt(N)元素。

現在我們使用O(N)時間來找到每個組的最小值,並將它們存儲到另一個數組調用M

因此,使用上述數組, M[0] = min(A[0..2]), M[1] = min(A[3..5]), M[2] = min(A[6..8]), M[3] = min(A[9..9])

(TopCoder教程中的圖像正在存儲最小元素的索引

在此處輸入圖片說明


現在讓我們看看如何查詢:

對於任何范圍[p..q] ,我們始終可以最多將其分為3個部分。

左邊界的兩個部分是一些不能組成一個整體的剩余元素。

一部分是介於兩者之間的元素,它們構成了一些組。

使用相同的示例, RMQ(2,7)可以分為三部分:

  1. 左邊界(元素上方): A[2]
  2. 右邊界(元素上方的剩余部分): A[6], A[7]
  3. 在元素之間(整個組中的元素): A[3],A[4],A[5]

注意,對於元素之間的元素,我們已經使用M對其最小值進行了預處理,因此我們無需查看每個元素,而是可以查看和比較M ,它們中最多包含O(sqrt(N)) (畢竟是M的長度)

對於邊界部分,由於它們不能按照定義形成一個整體組,因此意味着它們最多為O(sqrt(N)) (畢竟,這是一個整體組的長度)

因此,結合兩個邊界部分以及元素之間的in的一部分,我們只需要比較O(3*sqrt(N)) = O(sqrt(N))元素

您可以參考該教程以獲取更多詳細信息(甚至包括某些偽代碼)。

您可以使用Linq擴展方法來執行此操作。

    List<int> numbers = new List<int> {2, 1, 3, 1, 2, 3, 1, 3, 3, 2};

    int minindex =1, maxindex =3, minimum=-1;

    if(minindex <= maxindex && maxindex>=0  && maxindex >=0 && maxindex < numbers.Count())
    {
        minimum = Enumerable.Range(minindex, maxindex-minindex+1) // max inclusive, remove +1 if you want to exclude
            .Select(x=> numbers[x])    // Get the elements between given indices
            .Min();                    // Get the minimum among.    
    }

檢查這個Demo

形成如下循環:

int[] inputArray = { 2, 1, 3, 1, 2, 3, 1, 3, 3, 2 };
int minIndex = 2;
int maxIndex = 5;
int minVal = 3;
for (int i = minIndex; i <= maxIndex; i++)
{
    if (inputArray[i] <= minVal)
        minVal = inputArray[i];
}
Console.WriteLine("Minimum value in the Given range is ={0}", minVal);

這似乎是一個有趣的小問題。 我的第一點是,掃描固定陣列的速度通常非常快(每秒數百萬),因此您需要大量數據才能保證使用更復雜的解決方案。

顯而易見的第一件事是,當您找到1時,便從循環中中斷,因為那時您已找到最低值。

如果您想要更高級的東西。

  1. 創建一個新的int數組。 創建一個預加載函數,該函數使用較低的下一個索引填充該數組的每個項目。
  2. 創建一個使用新數組跳過的循環。

這就是我的意思。 取以下數組。

int[] intialArray = new int[] { 3, 3, 3, 3, 2, 2, 2, 1 };

int[] searchArray = new int[] { 4, 4, 4, 4, 7, 7, 7, 7 };

因此,想法是在位置0-7之間找到最低的位置。

initialArray[0]並獲取值3。
讀取searchArray[0]並獲取值searchArray[0]是數字較小的下一個索引。 讀取initialArray[4]並獲得值2。

等等

因此,基本上,您需要付出一些努力來構建搜索數組,但是一旦完成搜索,您將可以更快地掃描每個范圍。

暫無
暫無

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

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