手撕二分查詢及其變種,就是幹!
一、初探二分查詢
在面試的時候,尤其的一面,感覺讓你手寫二分,還真的不一定就能很快寫出來,所以在此總結分享給大家
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;
}
六 結尾
好了,今天文章就到這了,如果你讀到這裡了,老鐵麼麼噠!非常感謝!
點關注,不跑路
文章會首於與微信,可以微信搜尋[我是程式設計師小賤]第一時間檢視。
後面每週都會更新幾篇面試高頻題目和自己總結的文章,如果覺得學到了一點東西,來個三連擊,點贊,關注,分享。
創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文章見!
如果本篇部落格有任何錯誤,請批評指教,不勝感激 !
相關推薦
手撕二分查詢及其變種,就是幹!
一、初探二分查詢 在面試的時候,尤其的一面,感覺讓你手寫二分,還真的不一定就能很快寫出來,所以在此總結分享給大家 1 二分查詢是什麼? ”查詢“顧名思義是在一堆數去找出我們需要的數,但是我們又想更快的找出我們需要找的數,所以我們就儘量的減少查詢比較的次數。"二分"就是分成兩份來減少
C++:採用vector實現二分查詢及其變種總結
主要分為六種情況,閉區間,半開區間,中位值在迴圈之外的半開區間二分查詢首個序列,中位值在迴圈之外的半開區間二分查詢末尾序列,以及中位值在迴圈之外的完全開區間二分查詢首個序列和中位值在迴圈之外的完全開區間二分查詢末尾序列:#include <iostream> #i
二分查詢及其變種演算法
[TOC] ## 前言 **概念**:二分查詢(Binary Search)演算法,一種針對有序資料集合的查詢演算法,也叫折半查詢演算法。 **思想**:二分查詢針對的是一個**有序的資料集合**( 升序或降序 ),查詢思想有點類似分治思想。每次都通過跟區間的中間元素對比,將待查詢的區間縮小為之前的一半,
面試前必知必會的二分查詢及其變種
>需要更多演算法動圖詳解,可以微信搜尋[袁廚的演算法小屋] 今天給大家帶來的是二分查詢及其變種的總結,大家一定要看到最後呀,用心滿滿,廢話不多說,讓導演幫我們把鏡頭切到袁記菜館吧! 袁記菜館內。。。。 > 店小二:掌櫃的,您進貨回來了呀,喲!今天您買這魚挺大呀! > > 袁廚:那
二分查詢及其擴充套件
#二分查詢及其擴充套件# 二分查詢法 時間複雜度 O(logn) 實現 遞迴 public int binarySearchV2(int
LeetCode-二分查詢的變種總結
二分查詢 二分查詢作為一種基礎演算法,在面試和筆試中也是經常遇到,然而這一演算法在不同的情形中也有不同的表現形式,下面是一些二分查詢演算法的變種總結。(以下程式碼均已實現) 時間複雜度: 二分查詢也稱為折半查詢,每次都能將查詢區間減半,這種折半特性的演算法時間複雜度為 O(logN)
優化的直接插入排序(二分查詢插入排序,希爾排序)
本博文向大家介紹了插入排序的三種實現:直接插入排序,二分查詢插入排序,希爾排序。詳細分析的其實現過程、時間複雜度和空間複雜度、穩定性以及優化改進策略。最後簡單的做了下效能測試。 直接插入排序 (一)概念及實現 直接插入排序的原理:先將原序列分為有序區和無序區,然後再經過比較和後移操作將無序
如何寫出正確的二分查詢?——利用迴圈不變式理解二分查詢及其變體的正確性以及構造方式
序言 本文以經典的二分查詢為例,介紹如何使用迴圈不變式來理解演算法並利用迴圈不變式在原始演算法的基礎上根據需要產生演算法的變體。謹以本文獻給在理解演算法思路時沒有頭緒而又不甘心於死記硬背的人。 二分查詢究竟有多重要?《程式設計之美》第2.16節的最長遞增子序列
Java(二分查詢演算法實現,分別使用遞迴和非遞迴方式)
public class BinarySearch { private int[] array; private int index; private int min; private int max; public BinarySearch(int[]
面試官:手撕十大排序演算法,你會幾種?
## 原文連結:[面試官:手撕十大排序演算法,你會幾種?](https://mp.weixin.qq.com/s/VdZ_CMS-RQszFYfoZ_zYqQ) ## 演示地址:[點選檢視演示](https://sm5hw8.coding-pages.com) > 在前面三期,介紹了動態規劃的兩個主要
查詢一個月最後一天的總用戶數,數據庫中沒有保存最好一天的數據,就查詢本月數據庫已存有的最後一天的數據
數據庫 ont har rom to_char popu lec 最大 track select total_user from a_user_no where date_time=(select max(date_time) from a_user_no whe
【51Nod - 1094】和為k的連續區間 (字首和,二分查詢)
題幹: 一整數數列a1, a2, ... , an(有正有負),以及另一個整數k,求一個區間i,ji,j,(1 <= i <= j <= n),使得aii + ... + ajj = k。 Input 第1行:2個數N,K。N為數列的長度。K為需
SDUST - Training F HDU2199 方程求解,二分查詢,精度控制
Description Now,given the equation 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,can you find its solution between 0 and 100; Now please try your lucky.
java實現二分查詢演算法,兩種方式實現,非遞迴和遞迴
java實現二分查詢演算法 1、概念 2、前提 3、思想 4、過程 4、複雜度 5、實現方式 1. 非遞迴方式 2. 遞迴方式
導彈攔截(最長子序列問題,二分查詢)
題目描述 某國為了防禦敵國的導彈襲擊,發展出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。 輸入導彈依次飛來的高度(雷
python之遞迴函式,二分查詢
遞迴函式 遞迴函式一直都是我們所覺得難理解的以一種方式,但其實,也很好理解的,遞迴函式就是自己呼叫自己。就是在重複的做同一件事情。只是有的時候,也最好不要使用遞迴函式,因為你的函式一旦呼叫,就要開闢新的記憶體空間。不利於程式的執行。python對你記憶體一個保護機制,預設只能遞迴到998
php通過手機號查詢歸屬地,使用免費介面,資料量6W+以上
函式名稱:get_mobile_area 引數列表:$mobile表示需要查詢的手機號 具體實現: function get_mobile_area($mobile){ &n
二分查詢和快速排序(應該不能執行,只是一些筆記)
#include<iostream> using namespace std; template<class Type> //二分查詢 int BinarySearch(Type a[],const Type& x,int l,int r) {//a[]排好的遞
js實現快速排序,二分查詢 (詳解,一次學會)
js中幾大演算法,最近看到網上各路大神的解答,都蠻好的,自己也來玩一玩 一,快速排序 大致分三步: 在資料集之中,選擇一個元素作為"基準"(pivot)。 所有小於"基準"的元素,都移到"基準"的左邊;所有大於"基準"的元素,都移到"基準"的右邊。 對"基準"左邊和右邊的兩個子集,不斷重複
二分查詢以及其有趣的使用
說到二分查詢可能大家會想到二分查詢的基本模板類似這樣的: /** * 二分查詢的基本實現 * 作用:對於一個已經從小到大排好序的陣列找出目標元素的索引值 * 時間複雜度為O(logn) * @param nums * @param targ