必須了解的程式設計基礎 二分搜尋小節

2021-10-24 11:43:38 字數 3998 閱讀 2033

給定乙個排序陣列和乙個目標值,在陣列中找到目標值,並返回其索引。如果目標值不存在於陣列中,返回它將會被按順序插入的位置。

你可以假設陣列中無重複元素。

示例 1:

輸入: [1,3,5,6], 5

輸出: 2

示例 2:

輸入: [1,3,5,6], 2

輸出: 1

示例 3:

輸入: [1,3,5,6], 7

輸出: 4

示例 4:

輸入: [1,3,5,6], 0

輸出: 0

按照二分法思路列舉示例歸納規律:[1,3,5,6]

begin = 0, end = 3, mid = 1; target = 5, 恰好是nums[mid].

target = 2, target < nums[mid] && target > nums[mid-1], 所以 返回 mid -1;

同樣地,當 target > nums[mid] && target < nums[mid+1], 返回 mid + 1;

target = 7, target > nums[mid], begin = mid + 1 = 2; mid = (2 + 3)/2 = 2;

target > nums[mid]; begin = mid + 1 = 2 + 1 = 3, mid = (3 + 3)/2 = 3;

target > nums[mid]; begin = mid + 1 = 4, 出現了越界情況, 此時應該返回mid+1。應該邊界 mid = nums.size()-1 返回mid + 1;

同樣地,對於左邊界越界時,當mid = 0時,返回0;

class

solution

end = mid -1;

}else

if(target > nums[mid]

) begin = mid +1;

}}return index;}}

;

小節:二分查詢的實質就是不斷更新mid,然後來鎖定要找的target,本題同樣也是這樣,不過不同的是本題還需要對mid周圍的值施加限制:target只能是出現在mid的左/右兩邊,或者是出現在左右邊界。

這個對mid周圍值施加限制條件的思想,還會在下一題中應用的到。

給定乙個按照公升序排列的整數陣列 nums,和乙個目標值 target。找出給定目標值在陣列中的開始位置和結束位置。

你的演算法時間複雜度必須是 o(l

ogn)

o(log n)

o(logn

) 級別。

如果陣列中不存在目標值,返回 [-1, -1]。

示例 1:

輸入: nums = [5,7,7,8,8,10], target = 8

輸出: [3,4]

示例 2:

輸入: nums = [5,7,7,8,8,10], target = 6

輸出: [-1,-1]

分析:

這個光靠舉例子是歸納規律還是有點難度的,需要分析一下;

如果光靠二分法能不能找到左右端點?顯然不能,二分查詢最短只能找到乙個目標值的位置或者確認這個值不存在。

既然二分法可以找到乙個目標值的位置,那麼也就能找到兩個端點,因為端點也是目標值。

從上面一題可以得知,二分查詢法就是不斷更新mid的值,從nums[mid]或者mid周圍的值來搜尋目標值的。

從[5,7,7,8,8,8,10]出發,如果mid指向最終間的那個8,即有 nums[mid] == target;由4可知,我們需要更新mid來查詢端點,要麼向左,要麼向右去更新mid,又因為一次查詢只能往乙個方向移動,但是左右端點位於兩個方向上,因此,需要對將左右兩個端點的查詢任務分開進行3

。查詢左端點:會有兩個情況:[5,7,7,8,8,8,10] 和 [8,8,8,10], 當 nums[mid] == target 時, 如果mid == 0 || target > nums[mid-1], 說明此時的mid是左端點,否則說明左端點在mid左面,即要將mid向左移動,又因為mid是通過begin和end更新的,所以令end = mid - 1來更新mid;剩餘的target < nums[mid]和 target > nums[mid] 情況和二分查詢法相同3

。查詢右端點:同樣會有兩個情況:[5,7,7,8,8,8,10] 和 [7,8,8,8], 當 nums[mid] == target 時, 如果mid == nums.size()-1 || target < nums[mid+1], 說明此時的mid是右端點,否則說明右端點在mid右面,即要將mid向右移動,又因為mid是通過begin和end更新的,所以令 begin = mid + 1;剩餘的target < nums[mid]和 target > nums[mid] 情況和二分查詢法相同3

class

solution

intleft_bound

(vector<

int>

& nums,

int target)

end = mid -1;

}else

if(target < nums[mid]

)else

if(target > nums[mid])}

return-1

;}intright_bound

(vector<

int>

& nums,

int target)

begin = mid +1;

}else

if(target < nums[mid]

)else

if(target > nums[mid])}

return-1

;}};

假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。

( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。

搜尋乙個給定的目標值,如果陣列中存在這個目標值,則返回它的索引,否則返回 -1 。

你可以假設陣列中不存在重複的元素。

你的演算法時間複雜度必須是 o(log n) 級別。

示例 1:

輸入: nums = [4,5,6,7,0,1,2], target = 0

輸出: 4

示例 2:

輸入: nums = [4,5,6,7,0,1,2], target = 3

輸出: -1

分析:同樣還是需要思考+舉例

旋轉陣列是個新概念,也一定有屬於自己的特點。通過示例和舉例,發現旋轉陣列的特點:如果區間[0, mid]和[mid, nums.size()-1]至少有乙個是單調遞增的。

如果對示例1使用二分查詢,mid 會一直向左更新,不會找到0;原因在於[4,5,6,7]恰好是遞增的。所以,現在問題變成,如何更新mid,使得程式能夠找到traget = 0;

先結合1.旋轉陣列的特點,確定target屬於[0, mid]和[mid, nums.size()-1]哪個區間。然後在所屬區間上進行mid更新操作。

class

solution

else

}else

if(nums[mid]

<= nums[end]

)else}}

return-1

;}};

二分查詢的實質就是不斷更新mid,然後來鎖定要找的target; 而mid的更新是通過begin和end來決定的, begin和end的更新決定下乙個mid值位於當前mid的左端還是右端。

1.1和1.2是通過對mid左右附近值的限定來實現target的查詢;

1.3是通過對mid更新方向的選擇來實現target的查詢。

↩︎ ↩︎

↩︎↩︎↩︎

↩︎

二分搜尋基礎演算法

分治演算法基本思想 將乙個規模為 n 的問題分解為 k 個規模較小的子問題,這些子問題相互獨立且與原問題相同 給定已排好序的 n 個元素 array 0 n 1 現要在這 n 個元素找出特定元素x 首先較容易想到的是用順序搜尋方法,逐個比較 array 0 n 1 中元素,直至找出元素 x 或搜尋整...

基礎程式設計 二分查詢

題目要求 本題要求實現二分查詢演算法。函式介面定義 position binarysearch list l,elementtype x 其中list結構定義如下 typedef int position typedef struct lnode list struct lnode l是使用者傳入的...

java基礎 二分搜尋法

每個人寫的二分搜尋法均不相同,非常有趣,自己在工作中寫過的乙個二分搜尋法,當然前提是資料已經是有序的,並且目標很明確,最大程度的降低比較次數,這個演算法的難點在於程式的結束條件的尋找。public static boolean dichotomysearch int datas,int target...