思路
二分查找必須是一個有序的數據集合, 每次都通過跟區間的中間元素對比, 將查找區間縮小為一半, 直到找到元素或者區間被縮小為 0
時間復雜度
O(logn)
每次查找區間的變化: n, n/2, n/4, n/8 ...... n/2^k
當 n/2^k = 1 時候, k 就是區間縮小的總次數, k = log2 n, 所以時間復雜度O(k) = O(log2 n)
具體實現
1. 普通方法
int search(int* nums, int numsSize, int target) {
int low = 0;
int high = numsSize -1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if(nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
2. 遞歸實現
int recursionSearch(int *nums, int low, int high, int target) {
if (low > high) return -1;
int mid = low + ((high - low) >> 1);
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
return recursionSearch(nums, mid + 1, high, target);
} else {
return recursionSearch(nums, low, mid - 1, target);
}
}
int search(int* nums, int numsSize, int target) {
return reverseSearch(nums, 0, numsSize -1, target);
}
leetcode
69. x 的平方根
int mySqrt(int x) {
if (x <= 1) return x;
int low = 2;
int high = x / 2;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (mid == x / mid) return mid;
if (mid < x / mid) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low - 1;
}
35 . 搜索插入的位置
int searchInsert(int* nums, int numsSize, int target) {
if(numsSize == 0) return 0;
if(nums == NULL) return 0;
int low = 0;
int high = numsSize -1;
while (low <=high) {
int mid = low + ((high - low) >> 1);
if (nums[mid] == target) return mid;
if (nums[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return high + 1;
}
劍指offer 11 題
輸入一個遞增數組的旋轉, 輸出旋轉數組的最小元素
例如數組 {3,4,5,1,2}, 是 {1,2,3,4,5}的一個旋轉, 數組的最小值為1
思路:
- 從頭遍歷數組, 找出最小的元素, 時間復雜度O(n)
- 最小元素剛好是兩個子數組的分界線, 可以用二分查找實現 O(logn)的查找
- (int)rotateArray:(int *)numbers length:(int)length {
if (numbers == NULL || length <= 0) return -1;
int low = 0;
int high = length - 1;
int mid = low; // 把排序數組前面的0個元素放到后面, 就是數組本身
while (numbers[low] >= numbers[high]) {
// 如果第一個指針指向第一個遞增數組的末尾, 第二個指針指向第二個遞增數組的開頭
// 那么 high 就是最小的數字
if (high - low == 1) {
mid = high;
break;
}
// 有可能開頭、結尾、中間的數字都是一樣, 沒辦法區分mid 是屬于哪個遞增的數組
if (numbers[low] == numbers[high] && numbers[low] == numbers[mid]) {
return [self minInOrder:numbers low:low high:high];
}
mid = low + ((high - low) >> 1);
if (numbers[mid] >= numbers[low]) {
low = mid;
} else if (numbers[mid] <= numbers[high]) {
high = mid;
}
}
return numbers[mid];
}
- (int)minInOrder:(int *)numbers low:(int)low high:(int)high {
int result = numbers[low];
for(int i = low + 1; i <= high; i++) {
if (result > numbers[i]) {
result = numbers[i];
}
}
return result;
}