阿牧路泽

哪有那么多坚强,无非是死扛罢了
  博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

给定一个有序整数序列(非递减序),可能包含负数,找出其中绝对值最小的元素,比如给定序列 -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 }