【问题标题】:Monotonic Pair - Codility单调对 - Codility
【发布时间】:2014-05-31 13:14:35
【问题描述】:

我刚刚在 Codility,遇到了一个任务,我无法找到目标 O(n) 效率的解决方案;我的解决方案运行时间为 O(n2)。如果有人能给我一个关于如何让它运行得更快的提示,我会非常高兴。这是任务。

给定一个由 N 个整数组成的非空零索引数组 A。

单调对是一对整数 (P, Q),满足 0 ≤ P ≤ Q

目标是找到索引相距最远的 monotonic_pair。更准确地说,我们应该最大化 Q - P 的值。只要找到距离就足够了。

例如,考虑数组 A,这样:

A[0] = 5
A[1] = 3
A[2] = 6
A[3] = 3
A[4] = 4
A[5] = 2

有十一个单调对:(0,0), (0, 2), (1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (3, 3), (3, 4), (4, 4), (5, 5)。最大距离为 3,在 (1, 4) 对中。

写一个函数:

类解决方案 { public int solution(int[] A); }

给定一个由 N 个整数组成的非空零索引数组 A,返回任何 monotonic_pairs 中的最大距离。

例如,给定:

A[0] = 5
A[1] = 3
A[2] = 6
A[3] = 3
A[4] = 4
A[5] = 2

该函数应返回 3,如上所述。

假设:

N 是 [1..300,000] 范围内的整数; 数组 A 的每个元素都是 [−1,000,000,000..1,000,000,000] 范围内的整数。 复杂性:

预期的最坏情况时间复杂度为 O(N); 预期的最坏情况空间复杂度为 O(N),超出输入存储(不计算输入参数所需的存储)。 可以修改输入数组的元素。

我的第一个想法解决方案(在 O(n2) 中运行):

    public static int solution(int[] A) {
    int max = 0;
    for(int i=0; i<A.length-1; i++) {
        for(int j=i+1; j<A.length; j++) {
            if(A[j] >= A[i] &&
                    (j - i) >= max) {
                max = j - i;
            }
        }
    }
    return max;
}

【问题讨论】:

标签: java algorithm


【解决方案1】:

MarcinLe's 优于 n^2,但仍以 nlogn 运行。您可以通过不每次都进行登录查找来进行优化。相反,同时向前迭代您的最大数组和输入 A[] 数组以保证线性时间。

int[] top = new int[A.length];
int max = -Integer.MAX_VALUE;
for (int i=A.length-1; i>=0; i--) {
    if (A[i] > max) max = A[i];
    top[i] = max;
}

int best = 0;
int curMaxIndex = 0;
for (int i=0; i<A.length; i++) {
    while(curMaxIndex < top.length && top[curMaxIndex] >= A[i])
        curMaxIndex++;
    if((curMaxIndex - 1 - i) > best)
        best = curMaxIndex - 1 - i
}

return best; 

【讨论】:

    【解决方案2】:

    创建一个以降序包含最大值的临时数组:

    int[] top = new int[A.length];
    int max = -Integer.MAX_VALUE;
    for (int i=A.length-1; i>=0; i--) {
        if (A[i] > max) max = A[i];
        top[i] = max;
    }
    

    所以你可以通过二分搜索快速找到它们:

    int find(int[] t, int min) {
        int s = 0;
        int e = t.length-1;
    
        if (t[e] >= min) return e;
    
        while (true) {
            int x = (s+e) / 2;
            if (x == t.length-1) return t.length-1;
            if (t[x] >= min && t[x+1] < min) return x;
    
            if (t[x] < min) e = x;
            else s = x;
        }
    }
    

    你有一个解决方案:

    int best = 0;
    for (int i=0; i<A.length; i++) {
        int c = find(top, A[i]) - i;
        if (c > best) best = c;
        if (best >= A.length-i) return best;
    }
    
    return best;
    

    【讨论】:

      【解决方案3】:

      还有另一种算法,基于寻找对之间的最大距离(对不起,PHP),它也有 O(n2) 复杂度:

      function solution($a) {
      
          $length = count($a);
      
          for($max = $length-1; $max > 0; $max-- ) {
              for($i = 0; $i < $length - $max ; $i++) {
                  if ($a[$i] <= $a[$i+$max]) {
                      return $max;
                  }    
              }
          }
      
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        我认为你必须考虑距离。这就像广度优先搜索。查找所有具有最大距离(数组大小)的对,然后是具有距离 - 1 的对,依此类推。我正在研究它,并将尝试提供一个 c++ 解决方案。

        【讨论】:

        • 这有时很快,但在最坏的情况下为 n^2。想想 [5,4,3,2,1] 上会发生什么。它会在返回长度 1 之前查看所有可能的组合。
        【解决方案5】:

        我遇到了类似的测试并选择在 C 中解决它。 我相信我的解决方案以 O(nlog(n)) 最坏情况和 O(1) 最佳情况运行。 现在我松散地使用 O(1),但这是很有可能的。

        基本上我使用了 2 个指针。一个从阵列尾部缓慢移动,一个从头部扫描每个发现。我立即在索引相距最远的对上打破循环,这些对恰好是使用这种方法首先计算出来的。

        O(1) 成为可能,因为如果您计算的第一个单调对恰好位于列表的末尾和开头,那么这就是您的答案。没有比 this 更大的可能值要返回。

        int solution(int A[], int N) {
            // write your code in C90
            int p,q;
            // forward and backwards iterators
            int fi,bi=N-1;
            // track largest difference
            int diff=0;
        
            // interate through entire loop
            for(; bi >= 0; --bi){
               // Initialization
               p=q=bi;
               fi=0;
        
               // looking from the front
               for(fi=0; fi<bi; fi++){
                  if(A[fi] <= A[p] && A[q] >= A[fi] && fi<bi){
                     p=fi;
                     break;
                  }
               }
               if(diff < (q-p)){
                  diff = (q-p);
               }
        
               if(diff >= bi){
                  break;
               }
            }
            return diff;
        }
        

        【讨论】:

          【解决方案6】:

          我的解决方案但得到了 66%。它的 O(n**2) 时间复杂度。代码在 JavaScript 中。

          function solution(A) {
              var N = A.length;
              var distance = 0;
              for(var i = 0; i < N-1; i++) {
                  for(var j = i; j < N; j++){            
                      if(A[i] <= A[j]  && (j - i) > distance)
                          distance = j - i;
                  }
              }
              return distance;
          }
          

          【讨论】:

            猜你喜欢
            • 2020-09-19
            • 2023-04-09
            • 2014-12-21
            • 2015-02-19
            • 2013-10-28
            • 1970-01-01
            • 1970-01-01
            • 2011-08-09
            • 2016-03-10
            相关资源
            最近更新 更多