二分法終極解讀

2021-10-10 03:28:47 字數 3831 閱讀 2611

目錄

二分法是啥

1.最基本的二分法模組---尋找乙個數

最基本的二分法框架(左閉右開)

左閉右閉

2.尋找第乙個大於目標值的位置

3.尋找第乙個大於等於目標值的位置(左邊界)

4.其他採用二分法的題目

最近研究二分法,感覺對裡面的各種邊界及左右指標的指向產生了深深的懷疑,有時候要加等號,有時候要左閉右開區間,有時候要左開右閉區間。就很頭疼,就花時間仔細研究了一下,一點點寫左右指標移動的情況,最終略有所懂,分享一下。

說到二分法,就想到了以前中小學的乙個問題,有n個雞蛋,有乙個雞蛋比較重,其他都是一樣重,現在只有乙個平衡稱,怎麼最快進行找到這個比較獨特的雞蛋,就是一次分成兩堆,然後每次把重的那堆拿出來再進行比較。一直重複,直到找到。只需要logn次查詢就可以找到,縮短了原來的n次實驗。

二分查詢看起來其實很簡單,就是每次都分成一半,然後再去找,細節卻是魔鬼,要怎麼樣給mid值變換。它主要就是適用於單調的陣列,這個條件不能忘,不是所有的都能適用,一定是得具有單調性。接下來,我就詳細介紹二分法的各種場景

這個就是最基本的,給定你乙個陣列,然後再給乙個目標數target,在這個陣列裡面找到這個目標值的索引,找不到返回-1。

def binarysearch(nums,target):

''':param nums: 目標陣列

:param target: 目標元素

:return: 返回的目標元素的索引值,找不到的話返回-1

'''left=0

right=len(nums)

while(left>1

if (nums[mid]>target):

right=mid

elif(num[mid]首先就是這個左右指標的取值問題,現在是採用左閉右開的方式,即[left,right)咱就是在這個區間裡面去尋找目標值,首先先取一半,mid=(left+right)>>1向下取整,然後如果這個值就是目標值,那就直接返回,找到了。

如果不是那就是得判斷大了還是小了,當前值比目標值要大說明再左邊,就是把右邊界變成mid,那現在的區間就是[left,mid)因為mid已經判斷過了,所以不再進行判斷,如果是小了,就是在右邊,現在區間就是[mid,right),一下子就把要尋找的區域變成了一半,這就是二分法的真諦,不斷的去縮小搜尋區間找到最小值。

接著說一下最後退出的條件,因為是左閉右開的,最後一次進入判斷都是左右間隔為1,假如為[2,3)這個時候區間就只為2乙個值,進去mid=2判斷如果成功就返回,如果不成功就是要麼右邊界減1,要麼左邊界加1。然後就退出迴圈,返回-1。以上就是這個基本框架,那麼有人要問了我怎麼見過有的地方是right=len(nums)-1呢,別急,接下來就是要說這種情況。

def binarysearch(nums,target):

''':param nums: 目標陣列

:param target: 目標元素

:return: 返回的目標元素的索引值,找不到的話返回-1

'''left=0

right=len(nums)-1

while(left<=right):

mid=(left+right)>>1

if (nums[mid]>target):

right=mid-1

elif(num[mid]其實整體上只有3個變化,乙個是變成左閉右閉了,這樣就導致了迴圈退出條件得是left>right才能退出,為啥呢,因為假如現在區間是[2,2] 這個區間是乙個值,如果是left綜上,其實就是看初始化的取值,看區間是左閉右開還是左閉右閉,然後就通過這個搜尋區間去判斷迴圈退出條件區間變換值

當你看到這,能理解的話,恭喜你,你已經掌握了二分法的大部分真諦了。

相信這個題目也是比較清楚的,就是給你乙個陣列,然你去找第乙個大於目標值target的位置,這個題適用在哪呢,想想看,是不是在插入排序這塊就是用的這個東西。插入排序不就是在原陣列中每次拿出乙個值,找一下這個值應該放在哪,就是放在第乙個比這個數要大的位置。接下來我給個**再解釋下就清楚多了。

一般情況下左閉右開跟左閉右閉都是可以使用的,但是習慣性問題,***講的例子都採用左閉右開的方式

def search_loc(nums,target):

'''這個就是找第乙個比目標元素大的元素

:param nums: 目標陣列

:param target: 目標元素

:return: 返回的是插入位置 找到第乙個比目標值大的位置

'''left=0

right=len(nums)

while(left>1

if (nums[mid]>target):

right=mid

else:

left=mid+1

return left

最關鍵的點就是在於這個相等的情況,其他跟尋找對應元素的索引是一樣的。為啥這裡當找到目標元素的時候,咱要給他left=mid+1呢。這個就是要跟題目相關聯了,題目說找到比目標元素大的位置,所以說當mid值就是目標元素的時候,說明實際的位置區間應該在mid右邊,就是[mid+1,right)。

這裡要注意就是當mid比目標元素大,這個時候有可能這個mid就是咱要找的位置,但是現在區間變成[left,mid)乍一看這個目標值好像在現在要找的區間之外了,是不是丟了。其實不然,這個時候迴圈退出條件就很重要了,現在假如這個mid就是這個要求的值,那麼left會一直向他靠近,直到[mid-1,mid)然後最後一次判斷mid-1還是不滿足,left=mid-1+1 變成mid,迴圈退出。返回的位置還是這個mid。 是不是感覺很神奇?那麼這種情況就講完了,大家可以嘗試寫一下這個左閉右閉的情況。結果是一樣的,都是可以進行成功返回的。

當然這個模板也可以實現尋找目標值的右邊界,啥意思呢

就是比如[1,2,3,3,3,4,5] ,target=3 用這個方法 找到的就是4的索引值,如果return left-1 那麼返回的就是 3的最右邊了。其實思路是一樣的。改變的就是返回值減1就行了

這個也是題目的意思,還是按上面給的例子

[1,2,3,3,3,,4,5] 現在咱要要找的不是上面的那個了,要找的是第一大於等於目標值的位置,這個其實也叫左邊界

適用的就是有個最長上公升子串行有用到這個思路。

這個怎麼做呢,先不看**分析下,就是mid等於目標值的時候,是不是咱要找的值要麼是這個mid,要麼就是在他左邊,所以就是進行乙個右邊界的收縮。就是讓right=mid

def search_loc(nums,target):

''':param nums: 目標陣列

:param target: 目標元素

:return: 返回的是插入位置 這個就是找第乙個大於等於目標元素的位置

'''left=0

right=len(nums)

while(left>1

if (nums[mid]>=target):

right=mid

else:

left=mid+1

return left

其實跟上面那個右邊界的區別就是nums[mid]>=target ,就是當相等的時候,進行右邊界的收縮。

leetcode153.尋找旋轉排序陣列中的最小值

這裡大家可以先看看裡面的講解,都很精彩,我的理解就是左閉右開跟左閉右閉還有一些區別,就是採用左閉右閉如果採用leftleetcode278. 第乙個錯誤的版本

leetcode378. 有序矩陣中第k小的元素

C 二分法的解讀

注 一定是有序的陣列,才可以使用這種演算法,如果陣列沒有排序則先進行排序後再呼叫此方法。1 二分法是做什麼的呢?當然是查詢陣列中的資料了,開個玩笑,哈哈哈。2 為啥要用這種方式呢?二分顧名思義,就是將一組資料對半分開 比如左右兩部分,下面用左右陣列表示 從中間位置開始查詢,如果中間這個值正是咱們要找...

C 二分法查詢,遞迴二分法

用二分法來求需要查詢的值.includeusing namespace std 查詢key元素是否存在 int findkey const int buf 100 const int ilen,const int key else right left mid 1 查詢失敗 return 1 查詢k...

python二分法查詢 Python 二分法查詢

二分法查詢主要的作用就是查詢元素 lst 1,3,5,7,12,36,68,79 資料集 百萬級資料 num int input 請輸入你要查詢的元素資訊 for el in lst if num el print 存在 break else print 不存在 len lst 0 1 2 3 4 ...