代码之家  ›  专栏  ›  技术社区  ›  BCS

快速最小跨距

  •  2
  • BCS  · 技术社区  · 16 年前

    给定一个数组列表和大量的设置时间,我需要在每个数组的某个子跨度中快速找到最小值。在概念上:

    class SpanThing
    {
         int Data;
         SpanThing(int[][] data) /// must be rectangulare
         {
             Data = data;
             //// process, can take a while
         }
    
         int[] MinsBruteForce(int from, int to)
         {
             int[] result = new int[data.length];
             foreach(int index, int[] dat; Data)
             {
                 result[i] = int.max;
                 foreach(int v; dat[from .. to]);
                    result[i] = min(result[i], v);
             }
             return result;
         }
         int[] MinsSmart(int from, int to)
         {
              // same as MinsBruteForce but faster
         }
    }
    

    我目前的想法是在数据上构建一个二叉树,其中每个节点都包含相关跨度中的min。在一行的跨度中查找最小值的方法包括只查找组成它的树节点的最小值。该集合对于每一行都是相同的,因此可以计算一次。

    有没有人看到这个想法有什么问题,或者知道更好的方法?


    为了澄清,我所说的树将被设置为根节点将包含整行的最小值,对于每个节点,它的左子节点将具有父节点跨度左半部分的最小值,右半部分的最小值相同。

     0   5   6  2   7   9   4   1   7   2   8   4   2
     ------------------------------------------------
       | 5 | 6|   | 7 | 9 |   | 1 | 7 | 2 | 8 | 4 | 2  
     0 |   5  | 2 |   7   | 4 |   1   |   2   |   2  
       0      |   2       |   1       |       2
              0           |           1
                          0
    

    我正在优化的情况是,我有一个固定的输入集和大量的前期时间,但随后需要在各种跨度上进行许多快速测试。

    3 回复  |  直到 16 年前
        1
  •  2
  •   Norman Ramsey    16 年前

    您提出的解决方案似乎使用恒定的空间开销、恒定的时间设置和对数查询时间给出了答案。如果您愿意支付二次空间(即,提前计算所有间隔),您可以在固定时间内得到答案。您的对数方案几乎肯定是首选方案。

    如果有可能做得更好,我不会感到惊讶,但如果有一个 易于理解的

        2
  •  2
  •   Ryann Graham    16 年前

    你所描述的方法听起来像是在尝试做某种事情 memoization

    一般情况 最小值([0..n]) O(n)

    您的代码似乎更关心数组中的实际数字,而不是它们在数组中的顺序。如果要重复检查这些跨度,是否可以先对数据进行排序(可能是单个跨度) O(n日志n) 行动?大多数语言都有某种内置功能 sorting algorithm

        3
  •  0
  •   Zach Scrivena    16 年前

    这样一个简单的方法是否足够:假设 data 是一个nxm数组。我将创建一个M x M x N数组,其中 (i,j,k) 给出了 data(k,i:j)

    int[] getMins(int from, int to)
    {
        assert to >= from;
    
        if (mins[from][to] == null)
        {
            mins[from][to] = new int[N];
    
            // populate all entries (from,:,:)
            for (int k = 0; k < N; k++)
            {
                int t = array[k][from];
    
                for (int j = from; j < M; j++)
                {
                    if (array[k][j] < t)
                        t = array[k][j];
    
                    mins[from][j][k] = t;
                }
            }
        }
    
        return mins[from][to];
    }