1. 程式人生 > 實用技巧 >二分查詢思路以及可能出現情況對應解決辦法

二分查詢思路以及可能出現情況對應解決辦法

二分查詢

二分查詢又叫折半查詢,但是很容易寫錯,因為不好界定邊界

首先看一道二分查詢的題目
 135.搜尋插入位置
2給定一個排序陣列和一個目標值,在陣列中找到目標值,並返回其索引。如果目標值不存在於陣列中,返回它將會被按順序插入的位置。
3
4你可以假設陣列中無重複元素。
5
6示例1:
7
8輸入:[1,3,5,6],5
9輸出:2
10示例2:
11
12輸入:[1,3,5,6],2
13輸出:1
14示例3:
15
16輸入:[1,3,5,6],7
17輸出:4
18示例4:
19
20輸入:[1,3,5,6],0
21輸出:0
分析

二分查詢基礎條件是建立在有序陣列的基礎上,本題就是有序陣列,然後目標數字與陣列中各個值進行比較,

  1. 目標值比第一位元素小
  2. 目標值比最後一位元素大
  3. 目標值介乎於前倆種情況之間
解法1 暴力

從第一位遍歷與目標值比較,確定位置,此處只說明思路,時間複雜度 o(n)

解法2 二分查詢

首先說明一下題目中說陣列無重複資料,所以暫且不考慮重複情況,重複情況在文末進行說明
首先確定題中的不變數[left,right],既[0,nums.length-1],左閉右閉區間
看一下我的寫法

 1/**
2*二分法首先確定不變數,既不變區間【0,nums.length-1】,左閉右閉區間
3*@paramnums
4*@param
target
5*@return
6*/

7publicintsearchInsert(int[]nums,inttarget){
8intleft=0;
9intright=nums.length-1;
10while(left<=right){
11//避免溢位
12intmiddle=left+((right-left)/2);
13if(nums[middle]<target){
14left=middle+1;
15}elseif(nums[middle]>target){
16right=middle-1;
17}else{
18returnmiddle;
19}
20}
21returnright+1
;
22}

小結
以上題目主要想說明二分前確定好區間,才能確定好邊界條件

二分查詢重複值問題

當我們遇到[1,2,2,2,2,2]或者[1,1,1,2]這種情況可能會出現死迴圈該如何解決。
其實這種情況只會出現在二分查詢的第三個判斷上,既
nums[middle] == target

所以只需要對這塊進行處理,既向左以及想有找到所有相同元素的下標,至於要取最左還是最右看你的需求,那麼看一下程式碼

 1else{//表示arr[mid]==val
2/*思路分析
31.在找到mid索引值,不要馬上返回
42.向mid索引值的左邊掃描,將所有滿足1000,的元素的下標,加入到集合ArrayList
53.向mid索引值的右邊掃描,將所有滿足1000,的元素的下標,加入到集合ArrayList
64.將ArrayList返回*/

7
8//向mid左邊掃描
9inttemp=mid-1;
10while(true){
11if(temp<0||arr[temp]!=val)//沒有找到就退出迴圈
12break;
13//執行到這裡說明找到了,就把找到的元素新增到集合中,繼續向左找
14indexList.add(temp);
15temp-=1;
16}
17indexList.add(mid);//加入已經找到了的元素【arr[mid]==val】
18//向mid右邊掃描
19temp=mid+1;
20while(true){
21if(temp>arr.length-1||arr[temp]!=val)
22break;
23//執行到這裡說明找到了,就把找到的元素新增到集合中,繼續向右
24indexList.add(temp);
25temp+=1;
26}
27returnindexList;
28}

測試用例 :int[] arr = {1, 2, 3, 5, 6, 6,6, 6, 7, 8, 9};
target = 6;
返回的 indexList 就是 [4,5,6,7]既為陣列中為6的下標;

總結

二分查詢

  1. 注意邊界條件
  2. 注意為有序陣列
  3. 注意陣列是否有重複元素
    確定以上問題之後二分問題就能迎刃而解了