数据结构与算法之美笔记(四)二分查找

二分查找

二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0。

二分查找引用场景的局限性:

1、二分查找依赖的是顺序表结构,简单点说就是数组。
2、二分查找针对的是有序数据。
3、数据量太小不适合二分查找。如果要处理的数据量很小,完全没有必要用二分查找,顺序遍历就足够了。不过,这里有一个例外。如果数据之间的比较操作非常耗时,不管数据量大小,我都推荐使用二分查找,比如字符串的比较,这种情况下二分查找能尽可能地减少比较次数。
4、数据量太大也不适合二分查找。其实这条是基于第一条的,因为数据量太大意味着开辟了一块很大的连续内存空间,这在数据的存储上显然已经是不合理的了。


通过IP地址来查找IP归属地的功能:是通过维护一个很大的IP地址库来实现的。地址库中包括IP地址范围和归属地的对应关系。


在这里插入图片描述
常规:查找值值等于给定值的元素

static int binarySearch(int[] arr, int value) {
        int len=arr.length;
        int left=0,right=len-1;
        while(left<=right){
            int mid=left+((right-left)>>1);
            if(arr[mid]<value){
                left=mid+1;
            }else if(arr[mid]>value){
                right=mid-1;
            }else{
                return mid;
            }
        }
        return -1;
    }

变体一:查找第一个值等于给定值的元素
即查找到当前元素值等于目标值后,判断当前位置前面是否还有同样等于目标值的元素,有的话就说明还不是第一个,即right=mid-1

static int binarySearch(int[] arr, int value) {
    int len=arr.length;
    int left=0,right=len-1;
    while(left<=right){
        int mid=left+((right-left)>>1);
        if(arr[mid]<value){
            left=mid+1;
        }else if(arr[mid]>value){
            right=mid-1;
        }else{
            if(mid==0||arr[mid-1]!=value){
                return mid;
            }else{
                right=mid-1;
            }
        }
    }
    return -1;
}

变体二:查找最后一个值等于给定值的元素
就是变体一小改一下

static int binarySearch(int[] arr, int value) {
   int len=arr.length;
     int left=0,right=len-1;
     while(left<=right){
         int mid=left+((right-left)>>1);
         if(arr[mid]<value){
             left=mid+1;
         }else if(arr[mid]>value){
             right=mid-1;
         }else{
             if(mid==len-1||arr[mid+1]!=value){
                 return mid;
             }else{
                 left=mid+1;
             }
         }
     }
     return -1;
 }

变体三:查找第一个大于等于给定值的元素

static int binarySearch(int[] arr, int value) {
        int len=arr.length;
        int left=0,right=len-1;
        while(left<=right){
            int mid=left+((right-left)>>1);
            if(arr[mid]<value){
                left=mid+1;
            }else if(arr[mid]>=value){
                if(mid==0||arr[mid-1]<value){
                    return mid;
                }else{
                    right=mid-1;
                }
            }
        }
        return -1;
    }

变体四:查找最后一个小于等于给定值的元素
懒得写了,就是变体三改下边界条件和大于小于号方向🤗

凡是用二分查找能解决的,绝大部分我们更倾向于用散列表或者二叉查找树。即便是二分查找在内存使用上更节省,但是毕竟内存如此紧缺的情况并不多。那二分查找真的没什么用处了吗?
实际上,上一节讲的求“值等于给定值”的二分查找确实不怎么会被用到,二分查找更适合用在“近似”查找问题,在这类问题上,二分查找的优势更加明显。比如今天讲的这几种变体问题,用其他数据结构,比如散列表、二叉树,就比较难实现了。

课后思考题:
对应力扣33
搜索旋转排序数组

class Solution {
    public int search(int[] nums, int target) {
        int len=nums.length;
        int left=0,right=len-1;
        while(left<=right){
            int mid=left+((right-left)>>1);
            if(nums[mid]==target){return mid;}
            if(nums[left]<=nums[mid]){
                //左半边有序
                if(nums[left]<=target&&target<nums[mid]){
                    right=mid-1;
                }else{
                    left=mid+1;
                }
            }else{
                //右半边有序
                if(nums[mid]<target&&target<=nums[right]){
                    left=mid+1;
                }else{
                    right=mid-1;
                }
            }
        }
        return -1;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值