1、二分查找
在一个数组中寻找一个目标值,暴力解法就是遍历一遍数组,时间复杂度是O(N)
利用数组是升序的这个特点,可以在数组中随机找一个值,比较一下这个值与target的大小,若比target小,则这个值左边的全部数都比target小,比较一次就可以排除掉很多值,若这个值比target大也是同理。这就是利用了数组的二段性
二段性:当发现一个规律,根据这个规律,选取一个点,能把这个数组分成两部分,即根据规律能够有选择性的舍弃一部分,然后在另一部分中继续寻找,此时就可以用二分查找
实际上也不一定要是二分,三分、四分、五分等都是可以的,只要能将数组分成两部分然后排除掉一部分,只不过二分的时间复杂度是最好的
那按二分,时间复杂度是多少呢?
可以计算出x是log以2为底x的对数,所以时间复杂度是O(logN)
注意:算mid时,可能会发生溢出,所以可以采用先算出区间长度,再除2,然后让left加上前面运算的结果
class Solution {
public:
// 左闭右闭
int search(vector<int>& nums, int target) {
int left = 0,right = nums.size() - 1;
while(left <= right)
{
//int mid = (left + right) / 2;
int mid = left + (right - left) / 2; // 防止溢出
if(nums[mid] < target) left = mid + 1;
else if(nums[mid] > target) right = mid - 1;
else return mid;
}
return -1;
}
};
朴素的二非模板
int search(vector<int>& nums, int target) {
int left = 0,right = nums.size() - 1;
while(...)
{
//int mid = (left + right) / 2;
int mid = left + (right - left) / 2; // 防止溢出
if(...) left = mid + 1;
else if(...) right = mid - 1;
else return ...;
}
return -1;
}
模板中的...是根据具体题目的二段性来填入,并且一定要是<=,因为[left,right]的区间内所有元素都是未知的
注意:mid的计算方式除了上面的两种写法,还有另外两种mid = (left + right + 1) / 2,
mid = left + (right - left + 1) / 2,这两种在奇数时与上面的没有区别,偶数时有,不过在朴素版本中是没有区别的,因为朴素版本只需要找到一个点来将数组划分为两个区域即可,这个点在那个位置均可,即使在1/3、1/4都可以