手撕二分查找及其变种,就是干!

一、初探二分查找

在面试的时候,尤其的一面,感觉让你手写二分,还真的不一定就能很快写出来,所以在此总结分享给大家

1 二分查找是什么?

”查找“顾名思义是在一堆数去找出我们需要的数,但是我们又想更快的找出我们需要找的数,所以我们就尽量的减少查找比较的次数。"二分"就是分成两份来减少我们查找次数。

不急不急,假设我们这里有十个数,我们来画图看看这是个什么神操作。

从上图我们知道,我们每次都和区间的中间项值进行比较,从而缩小查找区间的值。

2 时间复杂度?

这里我们假设搜索区间一共n个数,第一次切分n/2,第二次n/4,第三次n/8..........n/2(k).这是一个等比数列,n/2(k)=1,k=log2n,那么时间复杂度为logn.

二 、二分的注意事项

1 二分查找要求数据必须是有序的。
2 二分查找依赖于数组随机查找的特性,要求内存连续

三 、二分的实现

1 第一种小白写法

int BinarySerach(vector<int>& nums, int target) {
    int left = 0, right = nums.size();
    while (left < right) {
        int mid = (left+right)/2;
        if (nums[mid] == target) return mid;
        else if (nums[mid] < target) left = mid + 1;
        else right = mid;
    }
    return -1;
}

面试官发话了

2 方法二优化版
如果right和left比较的时候,两者之和可能溢出。那么改进的方法是mid=left+(right-left)/2.还可以继续优化,我们将除以2这种操作转换为位运算mid=left+((right-left)>>1).

哪有这么简单的事儿,大多数的笔试面试中可能会出现下面的几种情况。

四 、二分的各种变种

这里主要是看看原始数组有重复数的情况。

1 查找第一个值等于给定值的情况(查找元素7)
思路

首先7与中间值a[4]比较,发现小于7,于是在5到9中继续查找,中间a[7]=7,但是这个数7不是第一次出现的。那么我们检查这个值的前面是不是等于7,如果等于7,说明目前这个值不是第一次出现的7,此时更新rihgt=mid-1.ok我们看看代码

int BinarySerach(vector<int>& nums, int n,int target) {
    int left = 0, right = n-1;
    while (left <= right) {
        int mid = left+((right-left)>>1);
        if (nums[mid]>value)
        {
            right=mid-1;
        } else if(nums[mid]<value)
        {
            left=mid+1;
        }else
        {
            if((mid==0)||(nums[mid-1]!=value))
            {
                return mid;
            }else
            {
                left=mid-1;
            }
        }
    return -1;
}

2 查找最后一个值等于给定值的情况

假设nums[mid]这个值已经是最后一个元素了,那么它肯定是要找到最后一个值。如果nums[mid]的下一个不等于value,那说明nums[mid]就是我们需要找到最后一个等于给定值的值。

int BinarySerach(vector<int>& nums, int n,int target) {
    int left = 0, right = n-1;
    while (left <= right) {
        int mid = left+((right-left)>>1);
        if (nums[mid]>value)
        {
            right=mid-1;
        } else if(nums[mid]<value)
        {
            left=mid+1;
        }else
        {
            if((mid==n-1)||(nums[mid+1]!=value))
            {
                return mid;
            }else
            {
                left=mid+1;
            }
        }
    return -1;
}

3 查找第一个大于等于给定值的情况

1 如果nums[mid]小于要查找的值,那么我们需要查找在[mid+1,right]之间,所以此时更新为left=mid+1
2 如果nums[mid]大于给定值value,这个时候需要查看nums[mid]是不是我们需要找的第一个值大于等于给定值元素,如果nums[mid]前面没有元素或者前面一个元素小于查找的值,那么nums[mid]就是我们需要查找的值。相反
3 如果nums[mid-1]也是大于等于查找的值,那么说明查找的元素在[left,mid-1]之间,所以我们需要将right更新为mid-1

int BinarySerach(vector<int>& nums, int n,int target) {
    int left = 0, right = n-1;
    while (left <= right) {
        int mid = left+((right-left)>>1);
        if (nums[mid]>=value)
        {
            if(mid==0||nums[mid-1]<value)
            {
                return mid;
            }else
            {
                right=mid-1;
            }
        }else
        {
            left=mid+1;
        }
    return -1;
}

4 查找最后一个小于等于给定值的情况

1 如果nums[mid]小于查找的值,那么需要查找的值肯定在[mid+1,right]之间,所以我们需要更新left=mid+1
2 如果nums[mid]大于等于给定的value,检查nums[mid]是不是我们的第一个值大于等于给定值的元素

int BinarySerach(vector<int>& nums, int n,int target) {
    int left = 0, right = n-1;
    while (left <= right) {
        int mid = left+((right-left)>>1);
        if (nums[mid]>value)
        {
            right=mid-1;
        }else
        {
            if(mid==n-1||(nums[mid+1]>value))
            {
                return mid;
            }else
            {
                left=mid+1;
            }
        }
    return -1;
}

六 结尾

好了,今天文章就到这了,如果你读到这里了,老铁么么哒!非常感谢!
点关注,不跑路

文章会首于与微信,可以微信搜索[我是程序员小贱]第一时间查看。

后面每周都会更新几篇面试高频题目和自己总结的文章,如果觉得学到了一点东西,来个三连击,点赞,关注,分享。

创作不易,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !

原文地址:https://www.cnblogs.com/lanjianhappy/p/12238249.html

时间: 2024-10-05 05:04:47

手撕二分查找及其变种,就是干!的相关文章

面试现场:手撕二分查找算法

算法概述 二分搜索,也称折半搜索.对数搜索,是一种在有序数组中查找某一特定元素的搜索算法. 搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束:如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较.如果在某一步骤数组为空,则代表找不到.这种搜索算法每一次比较都使搜索范围缩小一半. 二分搜索在情况下的复杂度是对数时间,进行 O(log n)次比较操作(n在此处是数组的元素数量, O是大O记号, log 是对数).

二分查找及其变种简单易懂的模版

鉴于最近在网上看到的二分查找算法非常复杂,细节太多,不容易理解,下面给出几个实现简洁,又容易理解的代码模版. 首先,让我们记住最基本的二分查找模版: 在有序数组A中查找key,如果找到,返回位置索引,否则,返回-1; int BinarySearch(int A[], int n, int key) { int left = 0, right = n - 1; while (left <= right) { int mid = left + (right - left) / 2; if (A[m

[数据结构] 二分查找与变种二分查找

1.二分查找 二分搜索(binary search),也称折半搜索(half-interval search).对数搜索(logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法.搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束:如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较.如果在某一步骤数组为空,则代表找不到.这种搜索算法每一次比较都使搜索范围缩小一半. 除直接在一个数组

STL之二分查找:hdu 5178 ( BestCoder Round #31 1001 )

STL包含四种不同的二分查找算法,binary_search    lower_bound  upper_bound   equal_range.他们的作用域是已经排序好的的数组. ★binary_search试图在已排序的[first, last)中寻找元素value.如果找到它会返回true,否则返回false,它不返回查找位置. ★iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素. ★iterat

关于二分查找的总结

最近又重新拾起了一直很凌乱的二分查找,各种版本,有时候总是很难调对,今天就整理了一下. 最基础的二分查找是从非递减序的数组中查找某个元素是否在数组中,如果在的话,随意返回一个位置,如果没有这个元素,返回-1.那么就有了下面这个基础的算法 //查找目标元素在数组中的位置,任意一个都可以,如果没有返回-1 int Binary_search(int *arr, int n, int val) { int l = 0; int r = n - 1; while (l <= r) { int mid =

二分查找(Binary Search)的几种变种形式

二分查找的几种变种形式 二分查找是大家经常用而且也比较简单的一种算法,查找的时间复杂度为O(logn).wiki上的定义为: 是一種在有序陣列中尋找某一特定元素的搜尋演算法 搜尋過程從陣列的中間元素開始,如果中間元素正好是要尋找的元素,則搜尋過程結束:如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中尋找,而且跟開始一樣從中間元素開始比較.如果在某一步驟陣列為空,則代表找不到.這種搜尋演算法每一次比較都使搜尋範圍縮小一半. 简单的二分查找算法相信大家都会写,但是有时候经常

【面试必备】手撕代码,你怕不怕?

Part 1.生产者-消费者问题这绝对是属于重点了,不管是考察对于该重要模型的理解还是考察代码能力,这都是一道很好的考题,所以很有必要的,我们先来回顾一下什么是生产者-消费者问题: 问题简单回顾 如果想学习Java工程化.高性能及分布式.深入浅出.微服务.Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家. 生产者消费者问题(英语:Producer-consumer pr

二分查找法

今年是大年初四,晚上闲的没事儿干,在手机上随手写了二分查找法,对有序数组或者循环有序数组都挺管用! public int binarySearch(int []nums,int key){ return binarySearch(nums,key,0,nums.length); } public int binarySearch(int []nums,int key,int left,int right){ int mid = (left + right) / 2; if(left <= rig

【C/C++学院】(3)二维数组/二分查找法/指针/模块注射

1.二维数组 二维数组可以当做一个一维数组, 每一个元素又是一个一维数组. #include <stdio.h> #include <stdlib.h> void main() { int a[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { printf("%d,%d,%d,%x,%x &