找出有序数组中绝对值最小的数
假设数组是从小到大排序,数值可能为负数、0、正数。
思路一
可以一次性遍历一遍,找出绝对值最小值,此时时间复杂度为O(N),缺点是没有利用数组是有序的这一特点。
int getMinAbs(int[] num){ //当数组只有一个元素的情况直接返回 if(num.length == 1) return num[0]; //当数组非负时直接返回num[0],当数组非正时直接返回num[num.length-1] if(num[0] >= 0) return num[0]; else if(num[num.length-1] <= 0) return num[num.length-1]; int min = Math.abs(num[0]); for(int i=1; i<num.length; i++) min = Math.min(min, Math.abs(num[i])); return min; }
思路二
数组有序,可以利用二分查找的特性。中间的数是正数,往后找;中间的数是负数,往前找。
问题的本质是找到正数的最小值,或负数的最大值,分析以下几种情况:
数组为a[], 数组大小为n.
- n=1,没有商量的余地,直接返回
- a[0] * a[n-1] >= 0,说明这些元素同为负或同为正。要是a[0]>=0,返回a[0];否则返回a[n-1]
- a[0] * a[n-1] < 0,说明元素中既有正数,也有负数。此时计算中间位置mid = low + (high-low)/2,如果a[mid]*a[low] >=0说明a[mid]也为负数,缩小范围low=mid;如果a[mid]*a[high]>=0,说明a[mid]为正数,缩小范围high=mid。如果只剩两个元素,那么就比较他俩的绝对值,直接返回了绝对值小的数。
int getMinAbs(int[] num) { //当数组只有一个元素的情况直接返回 if(num.length == 1) return num[0]; //当数组非负时直接返回num[0],当数组非正时直接返回num[num.length-1] if(num[0] >= 0) return num[0]; else if(num[num.length-1] <= 0) return num[num.length-1]; //当数组有正有负时,返回最大的负数与最小的非负数中较小的那一个 int low = 0, high = num.length-1, mid = (low + high)/2; while(low < high){ if(num[mid] < 0) low = mid + 1; else if(num[mid] > 0){ if(num[mid] * num[mid-1] < 0) return Math.min(Math.abs(num[mid-1]), num[mid]); high = mid - 1; }else return num[mid]; mid = (low + high) / 2; } return 0; }