思路
二分查找必須是一個有序的數(shù)據(jù)集合, 每次都通過跟區(qū)間的中間元素對比, 將查找區(qū)間縮小為一半, 直到找到元素或者區(qū)間被縮小為 0
時間復(fù)雜度
O(logn)
每次查找區(qū)間的變化: n, n/2, n/4, n/8 ...... n/2^k
當(dāng) n/2^k = 1 時候, k 就是區(qū)間縮小的總次數(shù), k = log2 n, 所以時間復(fù)雜度O(k) = O(log2 n)
具體實現(xià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. 遞歸實現(xiàn)
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 題
輸入一個遞增數(shù)組的旋轉(zhuǎn), 輸出旋轉(zhuǎn)數(shù)組的最小元素
例如數(shù)組 {3,4,5,1,2}, 是 {1,2,3,4,5}的一個旋轉(zhuǎn), 數(shù)組的最小值為1
思路:
- 從頭遍歷數(shù)組, 找出最小的元素, 時間復(fù)雜度O(n)
- 最小元素剛好是兩個子數(shù)組的分界線, 可以用二分查找實現(xià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; // 把排序數(shù)組前面的0個元素放到后面, 就是數(shù)組本身
while (numbers[low] >= numbers[high]) {
// 如果第一個指針指向第一個遞增數(shù)組的末尾, 第二個指針指向第二個遞增數(shù)組的開頭
// 那么 high 就是最小的數(shù)字
if (high - low == 1) {
mid = high;
break;
}
// 有可能開頭、結(jié)尾、中間的數(shù)字都是一樣, 沒辦法區(qū)分mid 是屬于哪個遞增的數(shù)組
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;
}