演算法總結 二分查詢

2021-08-24 17:41:33 字數 4127 閱讀 9586

本文首發於我的個人部落格:尾尾部落

二分查詢法作為一種常見的查詢方法,將原本是線性時間提公升到了對數時間範圍,大大縮短了搜尋時間,但它有乙個前提,就是必須在有序資料中進行查詢。

二分查詢很好寫,卻很難寫對,據統計只有10%的程式設計師可以寫出沒有bug的的二分查詢**。出錯原因主要集中在判定條件和邊界值的選擇上,很容易就會導致越界或者死迴圈的情況。

下面對二分查詢及其變形進行總結:

public

intbinarysearch(int a, int target, int n)else

if(a[mid] > target)else

}return -1;

}

其中,有幾個要注意的點:

1. 迴圈的判定條件是:low <= high

2. 為了防止數值溢位,mid = low + (high - low)/2

3. 當a[mid]不等於target時,high = mid - 1low = mid + 1

leetcode參考:search insert position

a = [1,3,3,5,7,7,7,7,8,14,14]

target = 7

return 4

public

intbinarysearchlowerbound(int a, int target, int n)else

}if(low < a.length && a[low] == target)

return low;

else

return -1;

}

a = [1,3,3,5,7,7,7,7,8,14,14]

target = 7

return 7

public

intbinarysearchupperbound(int a, int target, int n)else

}if(high >= 0 && a[high] == target)

return high;

else

return -1;

}

此題以可變形為查詢第乙個大於目標值的數/查詢比目標值大但是最接近目標值的數,我們已經找到了最後乙個不大於目標值的數,那麼再往後進一位,返回high + 1,就是第乙個大於目標值的數。

劍指offer:數字在排序陣列中出現的次數

此題以可由第 2 題變形而來,我們已經找到了目標值區域的下(左)邊界,那麼再往左退一位,即low - 1,就是最後乙個小於目標值的數。其實low - 1也是退出迴圈後high的值,因為此時high剛好等於low - 1,它小於low,所以 while 迴圈結束。我們只要判斷high是否超出邊界即可。

a = [1,3,3,5,7,7,7,7,8,14,14]

target = 7

return 3

int low = 0, high = n, mid;

while(low <= high)else

}return high < 0 ? -1 : high;

此題以可由第 3 題變形而來,我們已經找到了目標值區域的上(右)邊界,那麼再往右進一位,即high + 1,就是第乙個大於目標值的數。其實high + 1也是退出迴圈後low的值,因為此時low剛好等於high + 1,它大於high,所以 while 迴圈結束。我們只要判斷low是否超出邊界即可。

a = [1,3,3,5,7,7,7,7,8,14,14]

target = 7

return 8

int low = 0, high = n, mid;

while(low <= high)else

}return low > n ? -1 : low;

6.1 查詢旋轉陣列的最小元素(假設不存在重複數字)
leetcode: find minimum in rotated sorted array

input: [3,4,5,1,2]

output: 1

public

intfindmin(int nums)

}return nums[left];

}

注意這裡和之前的二分查詢的幾點區別:

1. 迴圈判定條件為left < right,沒有等於號

2. 迴圈中,通過比較nums[left]與num[mid]的值來判斷mid所在的位置:

最後,left會指向最小值元素所在的位置。

6.2 查詢旋轉陣列的最小元素(存在重複項)

leetcode: find minimum in rotated sorted array ii

劍指offer:旋轉陣列的最小數字

input: [2,2,2,0,1]

output: 0

public

intfindmin(int nums)

return nums[left];

}

和之前不存在重複項的差別是:當nums[mid] == nums[right]時,我們不能確定最小值在mid的左邊還是右邊,所以我們就讓右邊界減一。

7.1 不考慮重複項

leetcode: search in rotated sorted array

法一:

public

intsearch(int nums, int target)

int offset = left;

left = 0;

right = len - 1;

while(left <= right)

return -1;

}

法二:其實沒有必要找到旋轉陣列的分界點,對於搜尋左側還是右側我們是可以根據mid跟high的元素大小來判定出來的,直接根據target的值做二分搜尋就可以了。

public

intsearch(int nums, int target) else

if(nums[mid] <= nums[right])

}return -1;

}

7.2 存在重複項
leetcode: search in rotated sorted array ii

public

boolean

search(int nums, int target) else

if(nums[mid] < nums[right])else

}return

false;

}

劍指offer:二維陣列中的查詢

二維陣列是有序的,從右上角來看,向左數字遞減,向下數字遞增。因此可以利用二分查詢的思想,從右上角出發:

二分查詢 演算法總結

二分查詢也稱折半搜尋,是一種在有序陣列中查詢某一特定的元素的搜尋演算法。class solution else if nums mid mid left right 2 在left和right都很大的時候會出現溢位的情況,從而導致陣列訪問溢位。改進方法將加法變為減法 mid left right l...

演算法總結 二分查詢

二分查詢法作為一種常見的查詢方法,將原本是線性時間提公升到了對數時間範圍,大大縮短了搜尋時間,但它有乙個前提,就是必須在有序資料中進行查詢。二分查詢很好寫,卻很難寫對,據統計只有10 的程式設計師可以寫出沒有bug的的二分查詢 出錯原因主要集中在判定條件和邊界值的選擇上,很容易就會導致越界或者死迴圈...

二分查詢演算法c語言 演算法總結 二分查詢法

在leetcode的題目討論中,經常會有些大神將某一類的題目結題思路給整理了出來,感覺受益匪淺。受之啟發,萌生了自己也總結一下常見演算法的解題思路的想法,希望可以讓自己在這個總結的過程中可也融匯貫通這些思路,同時可以給後來者以啟發。從 開始好呢?就從經典的二分查詢法開始吧,這個演算法幾乎所有學過計算...