手撕二分查找及其變種,就是幹!

1、初探二分查找

在面試的時候,尤爲的一面,感受讓你手寫二分,還真的不必定就能很快寫出來,因此在此總結分享給你們程序員

在這裏插入圖片描述

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).
在這裏插入圖片描述3d

哪有這麼簡單的事兒,大多數的筆試面試中可能會出現下面的幾種狀況。code

四 、二分的各類變種

這裏主要是看看原始數組有重複數的狀況。
在這裏插入圖片描述
1 查找第一個值等於給定值的狀況(查找元素7)
思路blog

首先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;
}

在這裏插入圖片描述

六 結尾

好了,今天文章就到這了,若是你讀到這裏了,老鐵麼麼噠!很是感謝!
點關注,不跑路

文章會首於與微信,能夠微信搜索[我是程序員小賤]第一時間查看。

後面每週都會更新幾篇面試高頻題目和本身總結的文章,若是以爲學到了一點東西,來個三連擊,點贊,關注,分享。

創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!

若是本篇博客有任何錯誤,請批評指教,不勝感激 !
在這裏插入圖片描述

相關文章
相關標籤/搜索