Leetcode刷題系列(二)Binary Search
Binary Search的基礎框架程式碼
Bianry Search的基本思想
二分查詢法是基於一組有序數上的查詢,它的時間複雜度最壞為O(n),平均時間複雜度為O(lgn),空間複雜度為O(1)。由於它不需要藉助額外的空間,並且大多數情況下(平均)效能較好,所以是應用較廣的一種查詢法。
接下來介紹一些其他查詢方法的時間和空間複雜度:
查詢演算法 | 平均時間複雜度 | 最壞時間複雜度 | 空間複雜度 |
---|---|---|---|
順序查詢 | O(n) | O(n) | O(1) |
二分查詢 | O(lgn) | O(n) | O(1) |
二叉樹查詢 | O(lgn) | O(lgn) | O(n) |
雜湊查詢 | O(1) | O(1) | O(n) |
二叉樹查詢需要在原有資料的基礎上建立二叉排序樹,因此需要額外的空間,比較適合多次連續查詢。類似的演算法有雜湊查詢,需要額外空間建立雜湊表,同時考慮衝突處理等問題。
可以看出,二叉查詢是比較適合不知道查詢次數的情況。因為他不需要建立額外儲存結構。
Bianry Search的基礎框架程式碼
該程式碼為實現在有序陣列中查詢某個目標數的基本框架,與二叉查詢有關的其他題型可在此框架上進行修改。
public int findPosition(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int start = 0, end = nums.length - 1;
while (start + 1 < end) {
int mid = start + (end - start) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
start = mid;
} else {
end = mid;
}
}
if (nums[start] == target) {
return start;
}
if (nums[end] == target) {
return end;
}
return -1;
}
該程式碼搜尋位置比較偏左,搜尋到的目標數可能的第一個位置為start。
Binary Search的相關題型
Search Insert Position
題目為搜尋目標數第一個出現的位置,如果找不到則返回其應該插入的位置。
換種思路可以有:搜尋源數組裡第一個大於等於目標數的位置,或者最後一個小於目標數的位置+1。這兩種思想需要充分利用start和end的位置關係。
Search a 2D Matrix I
題目為在一個二維陣列中搜索目標數。
解題思路有以下兩種:
- 由於二維數組裡的數是嚴格遞增的,因此可以將二維陣列看成一維陣列進行搜尋,每個數的下標可以看成是i×n+j。使用matrix[mid / column][mid % column]與目標數進行對比。
- 可以先搜尋行,再搜尋列。注意搜尋行的時候,去尋找第一個小於等於matrix[mid][0]的數,該數所在的行數即為所要找的行數。因此,退出迴圈之後要先與matrix[end][0]進行對比。
Search a 2D Matrix II
題目為寫出一個高效的演算法來搜尋m×n矩陣中的值,返回這個值出現的次數。這個矩陣具有以下特性:
- 每行中的整數從左到右是排序的。
- 每一列的整數從上到下是排序的。
在每一行或每一列中沒有重複的整數。
該二維陣列中的數並不是嚴格遞增的,因此不適合上題中的方法。但其可以看成是是在二維座標軸中進行向右或向上的行走。即初始時在左下角逐漸向右上角進行搜尋。程式碼片段:
while (x >= 0 && y < m) {
if (matrix[x][y] < target) {
y++;
} else if (matrix[x][y] > target) {
x--;
} else {
count++;
x--;
y++;
}
}
Find Peak Element
題目為返回任意一個峰值的位置。因此,應使A[mid]與A[mid + 1]和A[mid - 1]進行比較,最後的結果在A[start]和A[end]之間,所以還需要進行最後一次判斷,返回較大者。
First Bad Version
該題需要返回第一個錯誤的版本,要求呼叫次數較少。呼叫次數可以看成比較次數,某種意義上說也是時間複雜度,因此使用二分查詢很合適。使用上述框架,則可以考慮成尋找第一個位置上的SVNRepo.isBadVersion(mid)為ture的值。