【正确答案】
【答案解析】问题描述:有一个升序排列的数组,数组中可能有正数、负数或0,求数组中元素的绝对值最小的数,例如,数组{-10,-5,-2,7,15,50},绝对值最小的是-2。
求绝对值最小的数可以分为3种情况:①如果数组第一个元素为非负数,那么绝对值最小的数肯定为数组的第一个元素;②如果数组最后一个元素为负数,那么绝对值最小的数肯定是数组的最后一个元素;③数组中即有正数又有负数时,首先找到正数与负数的分界点,如果分界点恰好为0,那么0就是绝对值最小的数,否则通过比较分界点左右的正数与负数的绝对值来确定最小的数。对于上面的例子来说,正数与负数的分界点为-2和7。通过比较它们的绝对值从而确定-2的绝对值更小,因此-2就是要查找的数。
那么如何来查找正数与负数的分界点呢?最简单的方法仍然是顺序遍历数组,找出第一个非负数(前提是数组中既有正数又有负数),接着通过比较分界点两个数的值来找出绝对值最小的数。这种方法在最坏的情况下时间复杂度为O(n)。下面主要介绍采用二分法来查找正数与负数的分界点的方法。其主要思路为:取数组中间位置的值a[mid]。①a[mid]=0,那么这个数就是绝对值最小的数;②a[mid]>0,如果a[mid-1]<0,那么就找到了分界点,通过比较a[mid]与a[mid-1]的绝对值就可以找到数组中绝对值最小的数,如果a[mid-1]=0,那么a[mid一1]就是要找的数,否则接着在数组的左半部分查找;③a[mid]<0,如果a[mid+1]>0,那么通过比较a[mid]与a[mid+1]的绝对值即可,如果a[mid+1]=0,那么a[mid+1]就是要查找的数,否则接着在数组的右半部分继续查找。实现代码如下:
public class Test{
public static int getMinAbsoluteValue(int[]a){
if(a==null)
return Integer.MIN_VALUE;
int len=a.length;
if(len<1)
return Integer.MIN_VALUE;
//数组中没有负数
if(a[0]>=0)
return a[0];
//数组中没有正数
if(a[len-1]<=0)
return a[len-1];
int mid=0;
int begin=0;
int end=len-1;
int absMin=0;
//数组中既有正数又有负数
while(true){
mid=begin+(end-begin)/2;
//如果值等于0,那么就是绝对值最小的数
if(a[mid]==0){
return 0;
}//如果值大于0,那么正负数的分界点在左半部分
else if(a[mid]>0){
//继续在数组的左半部分查找
if(a[mid-1]>0)
end=mid-1;
else if(a[mid-1]==0)
return 0;
//找到正负数的分界点
else
break;
}//如果值小于0,在数组右半部分查找
else{
//在数组右半部分继续查找
if(a[mid+1]<0)
begin=mid+1;
else if(a[mid+1]==0)
return 0;
//找到正负数的分界点
else
break;
}
}
//获取正负数分界点出绝对值最小的值
if(a[mid]>0){
if(a[mid]<Math.abs(a[mid-1]))
absMin=a[mid];
else
absMin=a[mid-1];
}else{
if(Math.abs(a[mid])<a[mid+1])
absMin=a[mid];
else
absMin=a[mid+1];
}
return absMin;
}
public static void main(String[]args)throws Exception{
int[]a1={-10, -5, -2, 7, 15, 50};
int[]a2={2, 4, 6, 8, 27};
im[]a3={-13, -9, -7, -3};
int value=getMinAbsoluteValue(a1);
System.out.println(value);
value=getMinAhsoluteValue(a2);
System.out.println(value);
value=getMinAbsoluteValue(a3);
System.out.println(value);
}
}
程序运行结果为:
-2
2
-3