问题描述:
有一个升序排列的数组,数组中可能有正数,负数,0,求数组中元素的绝对值最小的数。
分析:
分三种情况:
1)如果数组第一个元素为非负数,那么绝对值最小的数肯定为数组的第一个元素。
2)如果数组的最后一个元素为负数,那么绝对值最小的数肯定为数组的最后一个元素。
3)数组中既有正数又有负数时,首先找到正数与负数的分界点,如果分界点恰好为0,那么0就是绝对值最小的数。否则比较分级诶按左右的正数与负数的绝对值来确定最小的数。
查找正数与负数的分界点:
1)顺序遍历数组,找出第一个非负数(前提是数组中既有正数又有负数),接着通过比较分界点两个数的值来找出绝对值最小的数。最坏情况下 的时间复杂度为O(n).
2)二分法查找正数与负数的分界点的方法。取数组中间位置的值为 a[mid] ,
a[mid] = 0, a[mid] 为绝对值最小的数
a[mid] > 0 , 如果a[mid-1] <0, 找到分界点,比较 a[mid] 与 a[mid-1] 的绝对值就可以找到数组中绝对值最小的数
如果 a[mid-1] = 0, a[mid-1] 就是要找的数
a[mid-1] > 0, 在数组的左半部分找
a[mid] < 0, 如果 a[mid +1] >0, 找到分界点,比较 a[mid] 与 a[mid + 1] 的绝对值就可以找到数组中绝对值最小的数
如果 a[mid+1] = 0, a[mid+1] 就是要找的数
a[mid+1] <0, 在数组的右半部分找
代码实现 :
private 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];
}
// 情况三:数组中包含正数,负数,0
int begin = 0;
int end = len-1;
int absMin = 0;//最小的绝对值
int mid = 0;//begin与end的中间位置
while(true){
mid = begin + (end-begin)/2;
if(a[mid] == 0){
return a[mid];
}else if(a[mid] > 0){
if(a[mid-1] > 0)
end = mid - 1;
else if (a[mid-1] == 0)
return 0;
else
break;//找到分界点
}//a[mid] > 0
else{
if (a[mid+1] < 0)
begin = mid+1;
else if (a[mid+1] == 0)
return 0;
else
break;//找到分界点
}//a[mid] < 0
}//while
// 比较分界点两个值的绝对值大小
if(a[mid] > 0){
if(Math.abs(a[mid-1]) > a[mid]){
absMin = a[mid];
}else{
absMin = a[mid-1];
}
}//a[mid] > 0
else{
if(Math.abs(a[mid]) > a[mid+1]){
absMin = a[mid+1];
}else{
absMin = a[mid];
}
}
return absMin;
}
测试代码:
@Test
public void test1(){
int[] a1 = {-10,-5,-2,7,15,50};
int[] a2 = {2,4,6,8,27};
int[] a3 = {-13,-9,-7,-3};
int value = getMinAbsoluteValue(a1);
System.out.println(value);
value = getMinAbsoluteValue(a2);
System.out.println(value);
value = getMinAbsoluteValue(a3);
System.out.println(value);
}