注意:二分查詢中關於mid的選取
while(left <= right) 和 while(left < right) 的區別
while(left < right)表示在區間中還剩下乙個元素的時候,停止迴圈
來自 leetcode @liweiwei1419 對於二分搜尋編碼的建議在迴圈體內考慮如何縮減待搜尋區間,也可以認為是在待搜尋區間裡排除一定不存在目標元素的區間;
根據中間數被分到左邊和右邊區間,來調整取中間數的行為;
如何縮小待搜尋區間
退出迴圈的時候,根據題意看是否需要單獨判斷最後剩下的那個數是不是目標元素。
邊界設定的兩種寫法:
使用二分查詢的要點
69. x 的平方根(簡單)
**
public int mysqrt(int x)
if (x < 4)
int left = 2;
int right = x / 2;
int mid = 0;
while (left <= right) else if (temp > x) else
}return (long)mid * (long)mid > x ? mid - 1 : mid;
}
注意:34. 在排序陣列中查詢元素的第乙個和最後乙個位置(中等)
那麼能不能通過調整二分查詢的一些策略,找到我們需要的位置呢?
**
public int searchrange(int nums, int target) ;
}if (nums.length <= 1) : new int ;
}int res = new int;
int left = 0;
int right = nums.length - 1;
// 找到第一次出現的位置
while (left < right) else
}res[0] = nums[right] != target ? -1 : right;
if (res[0] == -1) ;
}// 找最後一次出現的位置
left = right;
right = nums.length - 1;
while (left < right) else
}res[1] = nums[left] == target ? left : left - 1;
return res;
}
注意:81. 搜尋旋轉排序陣列 ii(中等)
找到i
時間複雜度為o(n),二分查詢時間複雜度為o(log n),總的時間複雜度為o(n)
**
public boolean search(int nums, int target)
if (nums.length == 1)
int flag = 0;
for (int i = 0; i < nums.length - 1; i++)
}return binarysearch(0, flag, nums, target) || binarysearch(flag + 1, nums.length - 1, nums, target);
}public boolean binarysearch(int left, int right, int nums,int target) else if (nums[mid] < target) else
}return false;
}
改進(來自leetcode官方題解)
時間複雜度 o(log n)
實現
public boolean search(int nums, int target)
if (nums.length == 1)
int left = 0;
int right = nums.length - 1;
while (left <= right)
if (nums[left] == nums[mid]) else if (nums[mid] <= nums[right]) else
} else else }}
return false;
}
要點:如何判斷哪邊有序?
154. 尋找旋轉排序陣列中的最小值 ii(困難)
記這個元素下標為i
參考3.4,制定策略
為什麼要使用right
進行判斷而不是使用left
?
**
public int findmin(int nums)
int left = 0;
int right = nums.length - 1;
int mid = 0;
while (left < right) else if (nums[right] == nums[mid]) else
}return nums[left];
}
注意540. 有序陣列中的單一元素(中等)
也就是說,
根據這樣的規律,即可推斷出單一元素是在mid
的 左邊還是右邊
**
public int singlenonduplicate(int nums)
if (nums.length == 1 || nums[0] != nums[1])
if (nums[nums.length - 1] != nums[nums.length -2])
int left = 0;
int right = nums.length - 1;
while (left <= right)
if (mid % 2 != 0) else
} else else }}
return 0;
}
注意4. 尋找兩個正序陣列的中位數(困難)
如果對時間複雜度的要求有 log,通常都需要用到二分查詢,這裡我是沒想出來有什麼好方法,後來看了官方題解後恍然大悟
對於某些情況,需要特殊處理
總結
每次縮減陣列之後,k要減去陣列減少的元素個數
**
public double findmediansortedarrays(int nums1, int nums2) else
}private int findkth(int nums1, int nums2, int k)
if (index2 == length2)
// 當 k=1 時退出迴圈
if (k == 1)
int half = k / 2;
// 這步操作保證了newindex不會超出陣列長度
int newindex1 = math.min(index1 + half, length1) - 1;
int newindex2 = math.min(index2 + half, length2) - 1;
int pivot1 = nums1[newindex1], pivot2 = nums2[newindex2];
// k要減去每次排除的元素個數
if (pivot1 <= pivot2) else
}}
03二分查詢
整數二分要注意邊界問題 不然特別容易出現死迴圈 二分的本質是邊界問題 1.mid l r 2 2.檢查mid處是否滿足性質 在二分左邊時不需要 1 二分右邊時需要 1 二分必須要保證有解 題目可能無解,我們可以通過最後的邊界來判斷題目是否有解 def main n,m map int,input s...
LeetCode 查詢 二分查詢
給定乙個 n 個元素有序的 公升序 整型陣列 nums 和乙個目標值 target 寫乙個函式搜尋 nums 中的 target,如果目標值存在返回下標,否則返回 1。示例 輸入 nums 1,0,3,5,9,12 target 9 輸出 4 解釋 9 出現在 nums 中並且下標為 4 輸入 nu...
leetcode 二分查詢
leetcode 29 給定兩個整數,被除數dividend和除數divisor。將兩數相除,要求不使用乘法 除法和 mod 運算子。返回被除數dividend除以除數divisor得到的商。演算法設計 用2進製的左移操作,每次對被除數左移1位,比較除數與被除數左移的後的大小關係,並在結果中加上左移...