【问题标题】:Find smallest number in given range in an array在数组中查找给定范围内的最小数字
【发布时间】:2016-06-15 15:24:31
【问题描述】:

嗨,我有一个大小为 N 的数组。数组值总是只有 1、2、3 个整数值。现在我需要找到给定数组索引范围之间的最小数字。所以例如array = 2 1 3 1 2 3 1 3 3 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 是数组大小,那么我最终会比较所有项目的最低值。所以我想知道是否有办法优化代码以提高效率???

【问题讨论】:

    标签: c# loops c#-4.0 optimization comparison


    【解决方案1】:

    我认为这是一个 RMQ(范围最小查询),并且有几种实现可能适合您的场景。

    这是一个不错的TopCoder Tutorial,涵盖了很多,我推荐其中两个:

    使用教程中的符号,将&lt;P, T&gt;定义为&lt;Preprocess Complexity, Query Complexity&gt;,有两种著名且常见的实现/数据结构可以处理RMQ:Square Rooting Array & @987654322 @。

    Segment Tree 很有名,但很难实现,但它可以解决&lt;O(n), O(lg n)&gt; 中的 RMQ,比 Square Rooting Array (&lt;O(n), O(sqrt(n))&gt;) 复杂度更高


    方根数组 (&lt;O(n), O(sqrt(n))&gt;)

    注意,这不是技术的正式名称,也不是任何数据结构,确实我不知道这个技术有没有正式的命名,因为我学会了它......但是我们走吧

    对于查询时间,它绝对不是解决 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教程中的图片是存储最小元素的index)


    现在让我们看看如何查询:

    对于任何范围[p..q],我们总是可以将这个范围分成最多3个部分。

    左边界的两个部分是一些不能形成一个整体的剩余元素。

    一部分是介于两者之间的元素,它们形成了一些组。

    使用同样的例子,RMQ(2,7) 可以分为 3 部分:

    1. 左边界(剩余元素):A[2]
    2. 右边界(剩余元素):A[6], A[7]
    3. 在元素之间(整个组的元素):A[3],A[4],A[5]

    注意,对于那些在元素之间的,我们已经使用M预处理了它们的最小值,所以我们不需要查看每个元素,我们可以查看和比较M,最多有O(sqrt(N))其中(毕竟是M的长度)

    对于边界部分,由于定义不能形成一个整体,所以最多有O(sqrt(N))个(毕竟是一个整体的长度)

    所以结合两个边界部分,一个部分在元素之间,我们只需要比较O(3*sqrt(N)) = O(sqrt(N))元素

    你可以参考教程了解更多细节(甚至是一些伪代码)。

    【讨论】:

    • 如果链接过期或者他们更改了内容,您的回答将变得更少和错误。所以请尝试添加链接中的重要注释,并将链接作为参考
    • @SHIVANGRANA 我该怎么办?刚开始只是给教程参考,有人说我的回答毫无意义,现在我给出一些解释,当然是根据参考,有人说完全照搬...
    【解决方案2】:

    您可以使用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

    【讨论】:

      【解决方案3】:

      这似乎是一个有趣的小问题。我的第一点是扫描固定阵列的速度往往非常快(每秒数百万),因此您需要大量数据来保证更复杂的解决方案。

      显而易见的第一件事是在找到 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] 并得到值4。4 是下一个数字较小的索引。 读取initialArray[4],得到值2。

      等等

      所以基本上你需要付出一些努力来构建搜索数组,但是一旦完成,你会更快地扫描每个范围。

      【讨论】:

        【解决方案4】:

        形成如下循环:

        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);
        

        【讨论】:

        • 我不是最初的“反对者”,但我也反对,因为您的解决方案在编程上并不复杂,它本质上是硬编码。对于每个人来说,为任何数组而不是硬编码的人类集合获取 minindex 会更有用。
        猜你喜欢
        • 2013-09-09
        • 1970-01-01
        • 2020-10-03
        • 2014-04-27
        • 1970-01-01
        • 2017-03-23
        • 1970-01-01
        • 1970-01-01
        • 2015-07-28
        相关资源
        最近更新 更多