清晰解题: 二分查找之最小绝对值查找

找出有序数组绝对值最小元素

题目要求: 给定一个有序整数数组,返回其中绝对值最小的元素。
例如数组【-5,2,0,1,3】则返回 0

此处很明显应该借用二分查找的思想,但是有几个细节还是值得注意。

  • 先修知识点:
    • 二分查找的非递归写法
      • 为叙述清晰,下文一律使用“线程栈“指代每个线程拥有的栈空间,用”栈“来指代数据结构意义上的栈。使用“堆”指代一个进程的堆空间。
      • 非递归实现的好处: 递归算法在递归深度过深时,会发生占“线程栈”溢出, 因为每一次函数调用都会占用更多的“线程栈”空间, 而每个线程拥有的栈空间是独立的,而且大小是预分配好的。
      • 非递归写法常常通过使用“栈”来保存递归调用中需要记录的信息,这部分空间可以来源于“堆”空间。 一个进程的多个线程会共享堆空间,通常堆空间相比线程栈的空间要大,且可以动态增加,因此更不容易发生溢出。

二分查找的非递归写法

非递归
# here the parameter n is the length of array
binary_search(int[] a, int n, int value)
{
    int left = 0
    int right = n-1

    while( left< = right) //易错
    {
           middle = left + (right - left)/ 2 

           ifa[middle] > value)
           {
                right = middle -1 //易错
           }
           else if ( a[middle] < value)
           {
                left = middle +1  //易错
            }
            else
            {
                return middle   
            }
    }
    return -1
}
  • 二分查找法的思想很简单,唯一需要主义的就是几个易错的点
    • 第8行whil循环条件是 left <= right 不是left < right
    • 第13行right = middle -1
    • 第21行left = middle -1

二分查找之最小绝对值查找

int absMin(int* array, int size)
{
    if(size == 1)
        return a[0];
    if(a[0] * a[size-1] >= 0)  //如果同符号,这里用乘法判断正负有可能发生溢出,为书写简便,在此不作修正
        return (a[0] >= 0) ? a[0] : a[size-1];
    else
    {
        int low = 0, high = size-1, mid;
        while(low < high) //易错
        {
            if(a[middle]==0) 
                return middle;  
                //此处不加也可以让后续的部分正确运行,但是加上可以减少无谓的对比。如果不加的话,遇到数组中间元素为0的情况,会一直循环到left和right相邻,且其中有一个位置的元素为0
            if(low + 1 == high)
                return abs(a[low]) < abs(a[high]) ? a[low] : a[high];
            mid = low + (high - low) / 2;
            if(a[low] * a[mid] >= 0) 
                low = mid;  //易错,
            if(a[high] * a[mid] >= 0)
                high = mid; //易错
        }
    }
}
  • 首先给定的数组有序, 因此先检查首位元素是否同符号,如果同符号, 则绝对值最小元素可以立刻给出(同正则为第一个元素, 同负则为最后一个元素)
  • 当数组不同符号时,运用二分查找的思想, 首先计算middle = (left + right)/2
    • 此处要注意与二分查找相似而不同的地方:
      • 得到middle后,需要判断middle是否为0
        • 如果为0, 则可以直接返回该元素位置作为绝对值最小的元素
        • 如果该位置不为0, 则判断其正负, 如果为正,则需检查middle-left是否大于1,因为middle-left = 1的情况是找到了该数组正负变化的边界, 需要比较边界处两个元素哪个绝对值比较小。 例如【-5.-3.-2.-1,2,4,6】,最终比较的应该是-1与2的绝对值大小
      • 尤其和二分查找不同的是, 循环中,由于每一次的middle都有可能是正负边界的元素,所以每一次循环中,left = middle 或 left = right 而不是 left = middle+1 或 right = middle - 1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值