二分查詢 整合

2021-09-20 10:32:53 字數 3974 閱讀 5004

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

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

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

public int binarysearch(int a, int target, int n)else if(a[mid] > target)else

}return -1;

}

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

迴圈的判定條件是:low <= high為了防止數值溢位,mid = low + (high - low)/2a[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 int binarysearchlowerbound(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 int binarysearchupperbound(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 int findmin(int nums) 

}return nums[left];

}

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

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

迴圈中,通過比較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 int findmin(int nums) 

return nums[left];

}

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

7.1 不考慮重複項

leetcode: search in rotated sorted array

法一:

public int search(int nums, int target) 

int offset = left;

left = 0;

right = len - 1;

while(left <= right)

return -1;

}

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

public int search(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:二維陣列中的查詢

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

迭代二分查詢二分查詢

在寫這篇文章之前,已經寫過了幾篇關於改迭代二分查詢主題的文章,想要了解的朋友可以去翻一下之前的文章 bentley在他的著作 writing correct programs 中寫道,90 的計算機專家不能在2小時內寫出完整確正的二分搜尋演算法。難怪有人說,二分查詢道理單簡,甚至小學生都能明確。不過...

1128 二分 二分查詢

時間限制 10000ms 單點時限 1000ms 記憶體限制 256mb 描述nettle最近在玩 艦 因此nettle收集了很多很多的船 這裡我們假設nettle氪了很多金,開了無數個船位 去除掉重複的船之後,還剩下n 1 n 1,000,000 種不同的船。每一艘船有乙個稀有值,任意兩艘船的稀有...

二分查詢及變種二分查詢

二分查詢也稱折半查詢 binary search 它的查詢效率很好。二分查詢有乙個要求是必須採用順序儲存結構,而且表種的元素是有序的。只有滿足這個條件我們才能使用二分查詢。查詢條件 查詢區域的左邊界,小於等於查詢區域的右邊界 查詢過程 1.迴圈條件 查詢條件 2.計算序列中間下標位置 3.如果待查詢...