繁体   English   中英

数组中的最大绝对差

[英]Maximum absolute difference in an array

我遇到了这个算法问题。 我能够实现 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| |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) 吗?

是的,您的解决方案仍然是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] 的符号)以相同的方式处理。

我们当然可以在这里使用一些数学。 尝试扩展您试图最大化的功能。 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))。

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

下面是我在 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;

}

正如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;
}

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

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

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

案例可以是 A[i]>A[j] 或 A[i]<=A[j] 并且同时 i>j 和 i<=j 可以是案例,因此使用这些条件我们可以制定 4 种不同的表达式,从而消除使用绝对运算符。

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

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

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

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;

这是您问题的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;
  }                    
}

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< i,j < 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;
        }
    }

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

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

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

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

这里要考虑三件事:

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

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

对于 2,您必须将数字转向更负数。

现在我们需要的是分别为两个数组找到 min 和 max 的差异,具有较大绝对值的将是答案。

实现参考

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

我不确定我们是否需要 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);

这也很好,以减少最后一步的额外行:

      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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM