考虑下面这个算法,它求的是数值数组中大小最接近的两个元素的差。
可对比看下求数组中两个元素差的最大值https://blog.csdn.net/fkyyly/article/details/83930343
算法: MinDistance(A[0..n-1])
//输入:数字数组 A[0..n-1]
//输出:数组中两个大小相差最少的元素的差值
dmin <- ∞
for i <- 0 to n-1 do
for j <- 0 to n-1 do
if i≠j and |A[[i]-A[j]| < dmin
dmin <- |A[i]-A[j]|
return dmin
尽可能改进该算法(如果有必要,完全可以抛弃该算法;否则,请改进该算法)
原算法遍历每一个元素对,时间复杂度为 O(n²)。这其中有一半的元素对是重复比较的。且在已知 a < b < c 而比较过了 a、b 的差的情况下,没必要再比较 a 和 c 的差。
改进该算法的思想时,先取前两个元素,小的为a,大的为b,result为b-a的值,然后依次取剩下的元素,将新元素 c 与 a、b 比较,存在如下三种情况
(1)如果 c ∈ (a,b),c在a和b之间,再根据 c 和 (a+b)/2 的大小来更新 a 或 b。
(2)如果 c<a<b,判断b-a与a-c的值大小,如果a-c<b-a那么调整ab的结果b=a,a=c
(3)如果a<b<c,判断c-b与b-a的值大小,如果c-b<b-a那么调整ab的结果a=b,b=c
时间复杂度为O(n)
/**
* 乱序数组找出其中最接近的两个数,并输出两个数的差值
* 首先分别找出最小值a和最大值b
* 然后依次遍历数组元素,将新元素 c 与 a、b 比较,
* 如果 c ∈ (a,b),再根据 c 和 (a+b)/2 的大小来更新 a 或 b
* 具体的是如果c>(a+b)/2 则a=c
* 如果c<(a+b)/2 则b=c
*/
public class ClosestTwoDataMinus {
int MinDistance(int A[])
{
int a,b,c,result;
a = A[0];
b = A[1];
//保证b大a小
if(a>b){
result=a;
a=b;
b=result;
}
result = b-a;
for(int i=2;i<A.length;i++){
c=A[i];
// c在中间
if(c>=a && c<=b){//(a,b)之外的数字,第一次没有用因为a和b是min和max,但是后面交换之后会有用的
if(2*c>=(a+b)){
a=c;
} else{
b=c;
}
}else if (c<a){//c在左边
int ba = b-a;
int ac = a-c;
if(ac<ba){
b = a;
a = c;
}
}else {//c在右边
int ba = b-a;
int cb = c-b;
if(cb<ba){
a = b;
b = c;
}
}
result = b - a;
}
System.out.println("b=" + b);
System.out.println("a=" + a);
return result;
}
public static void main(String[] args) {
ClosestTwoDataMinus closestTwoDataMinus = new ClosestTwoDataMinus();
int[] A = {-1, 5, 1, 100, 105, 107};
// int[] A = {1, 4, 5};
System.out.println(closestTwoDataMinus.MinDistance(A));
}
}