给定一个有序整数序列(非递减序),可能包含负数,找出其中绝对值最小的元素,比如给定序列 -5、-3、-1、2、8 则返回1。
分析:由于给定序列是有序的,而这又是搜索问题,所以首先想到二分搜索法,只不过这个二分法比普通的二分法稍微麻烦点,可以分为下面几种情况
如果给定的序列中所有的数都是正数,那么数组的第一个元素即是结果。
如果给定的序列中所有的数都是负数,那么数组的最后一个元素即是结果。
如果给定的序列中既有正数又有负数,那么绝对值的最小值一定出现在正数和负数的分界处。
为什么?因为对于负数序列来说,右侧的数字比左侧的数字绝对值小,如上面的-5、-3、-1,而对于整整数来说,左边的数字绝对值小,比如上面的2、8,将这个思想用于二分搜索,可先判断中间元素和两侧元素的符号,然后根据符号决定搜索区间,逐步缩小搜索区间,直到只剩下两个元素。
单独设置一个函数用来判断两个整数的符号是否相同
1 /* 2 给定一个有序整数序列(非递减序),可能包含负数,找出其中绝对值最小的元素,比如给定序列 -5、-3、-1、2、8 则返回1。 3 分析:由于给定序列是有序的,而这又是搜索问题,所以首先想到二分搜索法,只不过这个二分法比普通的二分法稍微麻烦点,可以分为下面几种情况 4 如果给定的序列中所有的数都是正数,那么数组的第一个元素即是结果。 5 如果给定的序列中所有的数都是负数,那么数组的最后一个元素即是结果。 6 如果给定的序列中既有正数又有负数,那么绝对值的最小值一定出现在正数和负数的分界处。 7 */ 8 #include <iostream> 9 #include <cmath> 10 11 using namespace std; 12 13 bool sameSign(int m, int n) 14 { 15 if((m>>31) == (n>>31)) 16 return true; 17 else 18 return false; 19 } 20 21 //找出一个非递减证书序列中绝对值最小的数 22 int getMinNumberAbsoluteValue(int *arr, int n) 23 { 24 if(n == 1) 25 return arr[n]; 26 if(sameSign(arr[0], arr[n-1])) 27 return arr[0] >= 0 ? arr[0] : abs(arr[n-1]); 28 29 //二分搜索 30 int mid, low = 0, high = n-1; 31 while(low < high) 32 { 33 if(low + 1 == high) 34 return abs(arr[low]) < abs(arr[high]) ? abs(arr[low]) : abs(arr[high]); 35 mid = (low + high) >> 1; 36 if(sameSign(arr[low], arr[mid])) 37 { 38 low = mid;//分界点就在mid处 39 continue; 40 } 41 if(sameSign(arr[high], arr[mid])) 42 { 43 high = mid; 44 continue; 45 } 46 } 47 return abs(arr[low]); 48 } 49 50 int main() 51 { 52 int arr[5] = {-5, -3, -1, 2, 7}; 53 54 cout << "arr中绝对值最小值的绝对值为:" << getMinNumberAbsoluteValue(arr, 5) << endl; 55 return 0; 56 }