【问题标题】:Maximum absolute difference in an array数组中的最大绝对差
【发布时间】:2016-10-26 21:47:34
【问题描述】:

我遇到了这个算法问题。我能够实现 O(n^2) 解决方案。有没有更好的方法在 O(n) 时间内做到这一点?

问题:

给定一个包含 N 个整数的数组A1, A2 ,…, AN。返回所有1 ≤ i, j ≤ N 的最大值f(i, j)f(i, j)定义为|A[i] - A[j]| + |i - j|,其中|x|表示x的绝对值。

示例

A=[1, 3, -1]

f(1, 1) = f(2, 2) = f(3, 3) = 0
f(1, 2) = f(2, 1) = |1 - 3| + |1 - 2| = 3
f(1, 3) = f(3, 1) = |1 - (-1)| + |1 - 3| = 4
f(2, 3) = f(3, 2) = |3 - (-1)| + |2 - 3| = 5

所以,我们返回 5。

我的回答:

public class Solution {
    public int maxArr(ArrayList<Integer> A) {
        int maxSum = 0;

        for(int i=1; i<=A.size()-1; i++){
            for(int j=i+1; j<=A.size(); j++){
                int tempSum = sum(A.get(i-1), A.get(j-1), i, j);

                if(tempSum > maxSum) {
                    maxSum = tempSum;
                }
            }
        }

        return maxSum;
    }

    public int sum(int Ai, int Aj, int i, int j) {
        return Math.abs(Ai-Aj) + Math.abs(i-j);
    }
}

在我的解决方案中,内部循环从 i + 1 运行到 N,因此最坏的情况是该循环的 N-1。我的整体解决方案还是 O(n^2) 吗?

【问题讨论】:

    标签: algorithm


    【解决方案1】:

    是的,您的解决方案仍然是 O(N^2)(N - 1) + (N - 2) + ... + 1 = N * (N - 1) / 2

    我将展示如何在线性时间内解决更一般的问题:给出二维空间中的点列表 (x[i], y[i]),找到两个最远的点(相对于曼哈顿距离)。

    1. 让我们找到以下点:max(x[i] + y[i]), max(-x[i] + y[i]), max(-y[i] + x[i ]) 和 max(-x[i] - y[i]) 在所有 i 中。

    2. 让我们计算列表中每个点与上一步中选择的四个点之间的距离,然后选择最大的一个。该算法在考虑4 * N 点对时显然在线性时间内有效。我声称它是正确的。

    3. 为什么?让我们固定一个点 (x[k], y[k]) 并尝试找到离它最远的点。考虑一个任意点 (x[i], y[i])。让我们扩展它们坐标之间差异的绝对值。假设它是x[i] + x[k] + y[i] + y[k] = (x[k] + y[k]) + x[i] + y[i]。第一项是常数。如果x[i] + y[i]不是所有i中的最大值,则(x[i], y[i])不可能是最远的。其他三种情况(取决于展开式中 x[i] 和 y[i] 的符号)以相同的方式处理。

    【讨论】:

    • 检查两个可能的轴的最大值还不够吗(即 max(+x,+y)/max(-x,-y) 和 max(+x,-y) /max(-x,+y)?
    • 其实是这样。如果您将距离转换为 L-infinity,这会变得更加清晰。然后你得到max(d(p1, p2)) = max(max(|x1+y1-x2-y2|, |x1-y1-x2+y2|)) 并且我之前评论中的任何一对都达到了最大值。
    • 我仍在尝试了解通用解决方案将如何帮助我。所以我可以使用你的方法在数组中找到两个最远的点,并将它们的值代入方程中以找到最大绝对差?
    • @Yeshwanth Venkatesh 您可以为所有 i 设置 x[i] = a [i] 和 y[i] = i。
    • @YeshwanthVenkatesh 是的,(A[i], i) 是每个 i 的一个点。在第 3 点中,有 4 种情况取决于两个差异的符号。我展示了其中之一。在第 1 点中,我只得到 4 个点来最大化四个值(x[i] + y[i] 等)。它不是凸包。这个属性只有四分。
    【解决方案2】:

    我们当然可以在这里使用一些数学。尝试扩展您试图最大化的功能。 F(i,j) = |A[i] - A[j]| + |i - j| 展开它会给我们 4 个 F 值。

     1. A[i] - A[j] + i - j   equals to [A[i] + i] - [A[j]+j]
     2. -A[i] + A[j] + i - j  equals to [-A[i] + i] - [-A[j]+j]
     3. A[i] - A[j] + j - i   equals to [A[i] - i] - [A[j]-j]
     4. -A[i] + A[j] + j - i  equals to [-A[i] - i] - [-A[j]-j]
    

    计算[A[i] + i],[-A[i] + i],[A[i] - i],[-A[i] - i]的最大值和最小值对于向量/数组中的所有元素。将其称为 max1,max2,max3,max4 和 min1,min2,min3,min4。

    你的答案是 Max((max1-min1),(max2-min2),(max3-min3),(max4-min4))。

    如果有人感兴趣,这里是问题链接:- Problem Link

    下面是我在c++中的实现

    int Solution::maxArr(vector<int> &A) {
    int max1 = INT_MIN,max2 = INT_MIN,max3 = INT_MIN,max4 = INT_MIN,ans = INT_MIN;
    int min1 = INT_MAX,min2 = INT_MAX,min3 = INT_MAX,min4 = INT_MAX;
    for(int i=0;i<A.size();i++){
        max1 = max(max1,A[i] + i);
        max2 = max(max2,A[i] - i);
        max3 = max(max3,-A[i]+i);
        max4 = max(max4,-A[i]-i);
    
        min1 = min(min1,A[i] + i);
        min2 = min(min2,A[i] - i);
        min3 = min(min3,-A[i]+i);
        min4 = min(min4,-A[i]-i);
    
    }
    
    
        ans = max(ans,max1 - min1);
        ans = max(ans,max2 - min2);
        ans = max(ans,max3 - min3);
        ans = max(ans,max4 - min4);
    
    return ans;
    

    }

    【讨论】:

    • 解释得很好。
    • 我有一个问题,假设我们在索引 i = i* 和 j = j* 处达到 max1-min1、max2-min2、max3-min3、max4-min4 中的最大值,我们怎么做确定 A[i*] ,A[j*] & i*,j* 确实满足产生最大 b/c 的比较条件,我们生成了所有组合而无需担心实际订单 b/w A[i* ] ,A[j*] & i*,j*
    【解决方案3】:

    Kraskevich 所述,我应用了相同的算法。代码复杂度为O(4*n)+O(4*n),从而使得整体复杂度O(n)

    这里是代码。

    int Solution::maxArr(vector<int> &A) {
    int n=A.size(),max1=INT_MIN,max2=INT_MIN,max3=INT_MIN,max4=INT_MIN,ans=INT_MIN;
    for(int i=0;i<n;i++){
        max1=max(max1,A[i]+i);
        max2=max(max2,-A[i]+i);
        max3=max(max3,A[i]-i);
        max4=max(max4,-A[i]-i);
    }
    for(int i=0;i<n;i++){
        ans=max(ans,max1-A[i]-i);
        ans=max(ans,max2+A[i]-i);
        ans=max(ans,max3-A[i]+i);
        ans=max(ans,max4+A[i]+i);
    }
    return ans;
    }
    

    【讨论】:

    • 你不需要两个循环,一个循环就可以完成
    【解决方案4】:

    O(N) 时间复杂度和 O(1) 空间复杂度解决方案

    通过使用绝对算子的简单数学概念,可以在 O(N) 时间和 O(1) 空间复杂度内解决这个问题。

    在去掉绝对运算符并应用特定条件后,我们可以将这个表达式推导出为 4 种不同的形式。

    cases 可以是 A[i]>A[j] 或 A[i]j 和 i

    之后,我们只需要通过对数字数组进行一次迭代来找到每个表达式可能的最大值。

    如果你在解决这个问题时仍然遇到困难,那么你可以参考视频解决方案

    视频链接:-https://youtu.be/Ov4weYCIipg

    【讨论】:

      【解决方案5】:
      public int maxArr(ArrayList<Integer> A) 
      {    
        int n=A.size(),max1=A.get(0),max2=A.get(0),int min1=A.get(0),min2=A.get(0),ans=0;
      
        for(int i=0;i<n; i++){
          max1=max(max1, A.get(i)+i);
          max2=max(max2, A.get(i)-i);
          min1=min(min1,  A.get(i)+i);
          min2=min(min2, A.get(i)-i);
        }
      
         ans = max(ans, (max2 - min2));
         ans = max(ans, (max1 - min1));
      
         return ans;
      }
      

      这里

      int max1 = INT_MIN, max2 = INT_MIN;
      int min1 = INT_MAX, min2 = INT_MAX;
      

      【讨论】:

        【解决方案6】:

        这是你的问题的java解决方案。

        public class Solution {
        public int maxArr(ArrayList<Integer> A) {
            if(A.size() < 2) return 0;
            int res =Integer.MIN_VALUE;
            int max1=Integer.MIN_VALUE,max2=Integer.MIN_VALUE,min1 = Integer.MAX_VALUE,min2=Integer.MAX_VALUE;
            for(int i =0; i < A.size(); ++i){
                max1 = Math.max(A.get(i) + i, max1);
                min1 = Math.min(A.get(i) + i, min1);
        
                max2 = Math.max(A.get(i) - i, max2);
                min2 = Math.min(A.get(i) - i, min2);
            }
        
            res = Math.max(max1-min1, res);
            res = Math.max(max2-min2, res);
            return res;
          }                    
        }
        

        【讨论】:

          【解决方案7】:

          从概念上讲,我可以想到一个非常简单的解决方案:

          这里给定我们需要最大化 |A[i] - A[j]| + |i - j| 这是什么意思 ? => 如果您考虑沿 x 轴的数轴上的数字,它将有助于可视化。

          让我们考虑第二部分:|i-j| => 如果您考虑一下 - 它代表任意两点之间的距离。距离也总是固定的。

          现在,如果我们能想出一种方法将这个距离添加到我们的数组中,这样它将 A[i] - A[j] 的距离增加一个固定的量 - 我们的问题就解决了一半。

          这里需要考虑三件事:

          1. 如果两者都是阳性怎么办
          2. 如果两者都是负数怎么办
          3. 如果一个是正的一个是负的怎么办

          请记住,您必须将 A[i] 和 A[j] 之间的距离增加固定数量。 对于 1 和 3,如果您将两个数字都向正方向移动它们的索引量,即 i 和 j。你的问题解决了。

          对于 2,您必须将数字移到更负的位置。

          现在我们只需要分别找出两个数组的最小值和最大值的差异, 绝对值较大的就是答案。

          【讨论】:

            【解决方案8】:

            f(i, j) = |A[i] - A[j]| + |i - j|可以通过以下方式简化(基于abs()的定义):

            a) (A[j]-j)-(A[i]-i)
            b) (A[j]+j)-(A[i]+i)
            c) (A[i]+i)-(A[j]+j)
            d) (A[i]-i)-(A[j]-j)
            

            for 0&lt; i,j &lt; N - a & d 类似,b & c 也是类似的。因此,如果我们可以计算A[i]-iA[i]+i 的数组并找到其中的最大差值,我们就会得到答案。

              public class Solution {
                    public int maxArr(ArrayList<Integer> A) {
                        int n = A.size();
                        int max = 0;
                        int []a = new int [n];
                        int []b = new int [n];
                        for(int i=0;i<n;i++){
                            a[i]=A.get(i)-i;
                            b[i]=A.get(i)+i;
                        }
                        Arrays.sort(a);
                        Arrays.sort(b);
                        max = Math.max(a[n-1]-a[0], b[n-1]-b[0]);
                        return max;
                    }
                }
            

            【讨论】:

              【解决方案9】:

              实现参考

              int Solution::maxArr(vector<int> &A) {
                  int max1 , max2 , min1 , min2;
                  max1 = max2 = INT_MIN;
                  min1 = min2 = INT_MAX;
                  int N = A.size();
                  for(int i=0;i<N;i++){
                      max1 = max(max1,A[i]+i);
                      max2 = max(max2,A[i]-i);
                      min1 = min(min1,A[i]+i);
                      min2 = min(min2,A[i]-i);
                  }
                  int ans = 0;
                  ans = max(ans,max1-min1);
                  ans = max(ans,max2-min2);
                  return ans;
              }
              

              【讨论】:

                【解决方案10】:

                我不确定我们是否需要 4 个箱子。如果我们打开mod,有4种情况:

                 a) (A[j]-j)-(A[i]-i)
                 b) (A[j]+j)-(A[i]+i)
                 c) (A[i]+i)-(A[j]+j)
                 d) (A[i]-i)-(A[j]-j)
                

                但是 (a) 和 (d) 是相同的。 (b) 和 (c) 也是如此。因此问题归结为 2 种情况。

                int max1 = INT_MIN , max2 = INT_MIN , min1 = INT_MAX , min2 = INT_MAX;
                
                for(int i = 0; i < A.size(); i++)
                {
                    max1 = max(max1 , A[i] + i);
                    min1 = min(min1 , A[i] + i);
                    max2 = max(max2 , A[i] - i);
                    min2 = min(min2 , A[i] - i);
                }
                
                return max(max1 - min1 , max2 - min2);
                

                【讨论】:

                • 你能解释一下为什么A,D/B,C是一样的吗?
                【解决方案11】:

                这样也可以,减少最后一步的多余行数:

                      int n=A.size(),max1=INT_MIN,max2=INT_MIN,min1=INT_MAX,min2=INT_MAX,ans=INT_MIN;
                  for(int i=0;i<n;i++){
                        max1=max(max1, A[i]+i);
                        min1=min(min1, A[i]+i);
                        max2=max(max2, -A[i]+i);
                        min2=min(min2, -A[i]+i);
                  }
                  ans = max((max1-min1), (max2 - min2));
                return ans;
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2017-10-05
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-07-12
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-09-18
                  • 1970-01-01
                  相关资源
                  最近更新 更多