document.write('
最简单的方法就是找出所有可能的组合,从所有的组合中找出最小的距离,但是显然这种方法的效率比
较低下。通过分析发现,当ai≤bi≤ci时,此时它们的距离肯定为Di=ci-ai。此时就没必要求bi-ai与ci-ai
的值了,从而可以省去很多没必要的步骤,下面分别详细介绍这两种方法。
 方法一:蛮力法
 最容易想到的方法就是分别遍历三个数组中的元素,对遍历到的元素分别求出它们的距离,然后从这
些值里面查找最小值,实现代码如下:
 def maxs(a,b,c):
 maxs=b if a<b else a
 maxs=c if maxs<c else maxs
 return maxs
 
 def minDistance(a,b,c):
 aLen=len(a)
 bLen=len(b)
 cLen=len(c)
 minDist=maxs(abs(a[0]-b[0]),abs(a[0]-c[0]),abs(b[0]-c[0]))
 dist=0
 i=0
 while i<aLen:
 j=0
 while j<bLen:
 k=0
 while k<cLen:
 #求距离
 dist=maxs(abs(a[i]-b[j]),abs(a[i]-c[k]).abs(b[j]-c[k]))
 #找到最小距离
 if minDist>dist:
 minDist=dist
 k+=1
 j+=1
 i+=1
 return minDist
 
 if __name__=="__main__":
 a=[3,4,5,7,15]
 b=[10, 12, 14, 16, 17]
 c=[20, 21, 23, 24, 37, 30]
 print "最小离为: "+str(minDistance(a, b, c))
 程序的运行结果为:
 最小距离为:5
 算法性能分析:
 这种方法的时间复杂度为O(l*m*n),显然这种方法没有用到数组升序这一特性,因此,该方法肯定不
是最好的方法。
 方法二:最小距离法
 假设当前遍历到这三个数组中的元素分别为ai,bi,ci,并且ai≤bi≤ci,此时它们的距离肯定为Di=ciai,那么接下来可以分如下三种情况讨论:
 (1)如果接下来求ai,bi,ci+1的距离,由于ci+1≥ci,此时它们的距离必定为Di+1=ci+1
-ai,显然
Di+1≥Di,因此,Di+1不可能为最小距离。
 (2)如果接下来求ai,bi+1,ci的距离,由于bi+1≥bi,如果bi+1≤ci,此时它们的距离仍然为Di+1=ciai;如果bi+1>ci,那么此时它们的距离为Di+1=bi+1
-ai,显然Di+1≥Di,因此,Di+1不可能为最小距
离。
 (3)如果接下来求ai+1,bi,ci的距离,如果ai+1<ci-|ci-ai
|,此时它们的距离Di+1=max(ci-ai+1,cibi
),显然Di+1<Di,因此,Di+1有可能是最小距离。
 综上所述,在求最小距离的时候只需要考虑第3种情况即可。具体实现思路为:从三个数组的第一个
元素开始,首先求出它们的距离minDist,接着找出这三个数中最小数所在的数组,只对这个数组的下
标往后移一个位置,接着求三个数组中当前遍历元素的距离,如果比minDist小,则把当前距离赋值给
minDist,依此类推,直到遍历完其中一个数组为止。
 例如给定数组:a=[3,4,5,7,15]; b=[10,12,14,16,17]; c=[20,21,23,24,37,30];
 1)首先从三个数组中找出第一个元素3,10,20,显然它们的距离为20-3=17;
 2)由于3最小,因此,数组a往后移一个位置,求4,10,20的距离为16,由于16<17,因此,当前数组
的最小距离为16;
 3)同理,对数组a后移一个位置,依次类推直到遍历到15的时候,当前遍历到三个数组中的值分别为
15,10,20,最小距离为10;
 4)由于10最小,因此,数组b往后移动一个位置遍历12,此时三个数组遍历到的数字分别为
15,12,20,距离为8,当前最小距离是8;
 5)由于8最小,数组b往后移动一个位置为14,依然是三个数中最小值,往后移动一个位置为16,当
前的最小距离变为5,由于15是数组a的最后一个数字,因此,遍历结束,求得最小距离为5。
 实现代码如下:
 def mins(a,b,c):
 mins=a if a<b else b
 mins=mins if mins<c else c
 return mins
 
 def maxs(a,b,c):
 maxs=b if a<b else a
 maxs=c if maxs<c else maxs
 return maxs
 
 def minDistance(a,b,c):
 aLen=len(a)
 bLen=len(b)
 cLen=len(c)
 curDist=0
 minsd=0
 minDist=2**32
 i=0#数组a的下标
 j=0#数组b的下标
 k=0#数组c的下标
 while True:
 curDist=maxs(abs(a[i]-b[j]),abs(a[i]-c[k]),abs(b[j]-c[k]))
 if curDist<minDist:
 minDist=curDist
 #找出当前遍历到三个数组中的最小值
 minsd=mins(a[i], b[j], c[k])
 if minsd=a[i]:
 i+=1
 if i>=aLen:
 break
 elif minsd==b[j]:
 j+=1
 if j>=bLen:
 break
 else:
 k+=1
 if k>=cLen:
 break
 return minDist
 
 if __name__=="__main__":
 a=[3,4,5,7,15]
 b=[10, 12, 14, 16, 17]
 c=[20, 21, 23, 24, 37, 30]
 print "最小距离为: "+str(minDistance(a,b,c))
 算法性能分析:
 采用这种算法最多只需要对三个数组分别遍历一遍,因此,时间复杂度为O(1+n1+n)。
 方法三:数学运算法
 采用数学方法对目标函数变形,有两个关键点,第一个关键点:
 max {|x1-x2|,|y1-y2|}=(|x1+y1-x2-y2|+|x1-y1-(x2-y2)|)/2 (公式1)
 我们假设x1=a[i],x2=b[j],x3=c[k],则
 Distance=max(|x1-x2|,|x1-x3|,|x2-x3|)=max(max(|x1-x2|,|x1-x3|),|x2-x3|) (公式2)
 根据公式1,max(|x1-x2|,|x1-x3|)=1/2(|2x1-x2-x3|+|x2-x3|),带入公式2,得到
 Distance=max(1/2(|2x1-x2-x3|+|x2-x3|),|x2-x3|)=1/2*max(|2×1-x2-x3|,|x2-x3|)+1/2*|x2-x3|//
把相同部分1/2*|x2-x3|分离出来
 =1/2*max(|2x1-(x2+x3)|,|x2-x3|)+1/2*|x2-x3|//把(x2+x3)看成一个整体,使用公式1
 =1/2*1/2*((|2x1-2x2|+|2x1-2x3|)+1/2*|x2-x3|
 =1/2*|x1-x2|+1/2*|x1-x3|+1/2*|x2-x3|
 =1/2*(|x1-x2|+|x1-x3|+|x2-x3|)//求出等价公式,完毕!
 第二个关键点:如何设计算法找到(|x1-x2|+|x1-x3|+|x2-x3|)的最小值,x1,x2,x3,分别是三个数
组中的任意一个数,算法思想与方法二相同,用三个下标分别指向a,b,c中最小的数,计算一次它们
最大距离的Distance,然后再移动三个数中较小的数组的下标,再计算一次,每次移动一个,直到其中
一个数组结束为止。
 示例代码如下:
 def mins(a,b,c):
 mins=a if a<b elseb
 mins=mins if mins<c else c
 return mins
 
 def minDistance(a,b,c):
 aLen=len(a)
 bLen=len(b)
 cLen=len(c)
 MinSum=0# 最小的绝对值和
 Sum=0#计算三个绝对值的和, 与最小值做比较
 MinOFabc=0 # a[i], b[j], c[k]的最小值
 cnt=0# 循环次数统计, 最多是1+m+n次i=0, j=0, k=0//a,b,c三个数组的下标索引
 i=j=k=0
 MinSum=(abs(a[i]-b[j])+abs(a[i]-c[k])+abs(b[j]-c[k]))/2
 cnt=0
 while cnt<=aLen+bLen+cLen:
 Sum=(abs(a[i]-b[j])+abs(a[i]-c[k])+abs(b[j]-c[k]))/2
 MinSum=MinSum if MinSum<Sum else Sum
 MinOFabc=mins(a[i], b[j], c[k])# 找到a[i],b[j],c[k]的最小值
 #判断哪个是最小值, 做相应的索引移动
 if MinOFabc==a[i]:
 i+=1
 if i>=aLen:
 break # a[i]最小, 移动i
 if MinOFabc==b[j]:
 j+=1
 if j>=bLen:
 break #b[j]最小, 移动j
 if MinOFabc==c[k]:
 k+=1
 if k>=cLen:
 break #c[k]最小, 移动k
 cnt+=1
 return MinSum
 
 if __name__=="__main__":
 a=[3,4,5,7,15]
 b=[10,12,14,16,17]
 c=[20,21,23,24,37,30]
 print "最小距离为: "+str(minDistance(a, b, c))
 程序的运行结果为:
 最小距离为:5
 算法性能分析:

 与方法二类似,这种方法最多需要执行(1+m+n)次循环,因此,时间复杂度为O(1+m+n)。 

');