【问题标题】:Fast min on span跨度快速最小值
【发布时间】:2009-02-07 19:36:10
【问题描述】:

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

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
     }
}

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

有没有人发现这个想法有任何问题或知道更好的方法?


为了澄清,我正在谈论的树将被设置为根节点将包含整行的最小值,对于每个节点,它的左子节点将具有左半部分的最小值parent 的 span 和 right 相同。

 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

这棵树可以映射到一个数组并以这样一种方式定义,即可以计算段边界,从而实现快速查找。

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

【问题讨论】:

    标签: algorithm data-processing


    【解决方案1】:

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

    如果有可能做得更好,我不会感到惊讶,但如果有一个 简单 数据结构可以做得更好,我会感到震惊——实际上,对数时间几乎总是足够快。去吧。

    【讨论】:

    • 我实际上并不确定这是日志时间(至少在平均情况下)。我还没有坐下来详细解释它,但它可能会更好。无论如何+1 :)
    • 将数组扩展为 N=2**m 且无穷大。对数组进行二进制搜索,直到在跨度中找到一个点(即 k 步)。然后你必须向左走 m-k 步才能得到跨度的小端,向右走 m-k 步才能得到大端。成本在 m 到 2m 之间,其中 m = log N。
    • 我得考虑一下。我只是在考虑每行成本,如果跨度恰好与树中的某些内容匹配,则它的下限为 1。最坏的情况是除第一个和最后一个元素之外的所有元素的跨度,大约为 2 log n。更有趣的是一般情况。
    【解决方案2】:

    您描述的方法听起来像是您正在尝试执行某种memoization 或缓存,但这只会在您重复检查相同的跨度或嵌套的跨度时对您有所帮助。

    min([0..n]) 的一般情况将是 O(n),这就是你已经得到的。 p>

    您的代码似乎更关心数组中的实际数字,而不是它们在数组中的顺序。如果您要反复检查这些跨度,是否可以先对数据进行排序,这可能是单个 O(n log n) 操作,然后是一堆 O (1) 操作?大多数语言的标准库中都有某种内置的sorting algorithm

    【讨论】:

      【解决方案3】:

      尚不清楚如何使用您描述的树方法有效地表示区间层次结构。划分区间的方法有很多种——我们是否必须考虑每一种可能性?

      像这样的简单方法就足够了:假设data 是一个 N x M 数组。我将创建一个 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];
      }
      

      【讨论】:

        猜你喜欢
        • 2014-09-24
        • 2022-11-18
        • 1970-01-01
        • 1970-01-01
        • 2013-08-06
        • 1970-01-01
        • 1970-01-01
        • 2017-06-23
        • 1970-01-01
        相关资源
        最近更新 更多