我遇到了这个算法问题。我能够实现O(n ^ 2)解决方案。在O(n)时间有更好的方法吗?
问题:
您将获得一个N个整数数组A1, A2 ,…, AN
。对于所有f(i, j)
,返回1 ≤ i, j ≤ N
的最大值。
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)?
答案 0 :(得分:22)
是的,您的解决方案仍为O(N^2)
(N - 1) + (N - 2) + ... + 1 = N * (N - 1) / 2
。
我将展示如何在线性时间内解决更一般的问题:给出2D空间中的点列表(x [i],y [i]),找到两个最远点(相对于曼哈顿距离) )。
让我们找到以下几点:max(x [i] + y [i]),max(-x [i] + y [i]),max(-y [i]所有i中都有+ x [i])和max(-x [i] - y [i])。
让我们计算列表中每个点与上一步中选择的四个点之间的距离,然后选择最大的一个点。该算法在考虑4 * N
个点对时,在线性时间内明显起作用。我声称它是正确的。
为什么呢?让我们修一个点(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])
,则{{1}}不能最远。其他三种情况(取决于扩展中的x [i]和y [i]的符号)以相同的方式处理。
答案 1 :(得分:7)
我们可以在这里使用一些数学。尝试扩展您尝试最大化的功能。 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;
}
答案 2 :(得分:6)
如 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;
}
答案 3 :(得分:4)
O(N)时间复杂度和O(1)空间复杂度解决方案
通过使用绝对算子的简单数学概念,可以解决O(N)时间和O(1)空间复杂性的问题。
在删除绝对运算符并应用特定条件后,我们可以将这种表达推导为4种不同形式。
情况可以是A [i]> A [j]或A [i] <= A [j],同时i> j和i <= j可能是情况,因此使用这些条件,我们可以公式化4个不同的表达式消除了绝对运算符的使用。
此后,我们只需要对数字数组进行一次迭代即可找到每个表达式可能的最大值。
如果在解决此问题时仍然遇到任何困难,则可以参考视频解决方案
答案 4 :(得分:2)
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;
答案 5 :(得分:1)
这是解决问题的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;
}
}
答案 6 :(得分:1)
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
&amp; d
类似于b
&amp; c
。因此,如果我们可以计算A[i]-i
和A[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;
}
}
答案 7 :(得分:1)
从概念上讲,我可以想到一个非常简单的解决方案:
在这里,我们需要最大化| A [i]-A [j] | + | i-j | 这是什么意思 ? =>如果您想到x轴上数字线上的数字,将有助于可视化。
让我们想想第二部分:| i-j | =>如果您考虑这一点-它代表任意两点之间的距离。距离也总是固定的。
现在,如果我们可以想到一种将距离增加到数组中的方法,以使距离A [i]-A [j]增加固定量,则可以解决一半的问题。
这里要考虑三件事:
请记住,您必须将A [i]和A [j]之间的距离增加固定量。 如果您将两个数字都朝正方向移动了它们的索引值即i和j,则为1和3。您的问题已解决。
对于2,您必须将数字移向负数。
现在我们需要的是分别找到两个数组的最小值和最大值之差, 答案是绝对值大的人。
答案 8 :(得分:0)
实施参考
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;
}
答案 9 :(得分:0)
我不确定我们是否需要4种情况。如果我们打开国防部,则有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);
答案 10 :(得分:0)
这也很好,以减少最后一步的额外行:
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;