二分查找:
前提:在一个已经排好序的数组里,要找到一个目标值,这个时候二分查找就登场了!
我在数组最左边和最右边分别搞一个箭头,也就是left和right,有了他俩,我就能找到他俩最中间的数,也就是middle;
如果我发现这个middle上的数就是我要的目标值,皆大欢喜直接结束;
如果不是,我看我的目标值是比middle大还是小:
比middle大的话就说明我要的目标值在middle右边,这时候我还管middle左边干什么??直接把left放到原来middle的位置,新的middle就又出现了:
之后我就用新的middle去对比我的目标值,如果这次对了,皆大欢喜,如果不对,我就再看是比目标值大了还是小了,
大了,我就把left再换到middle的位置上,小了,我就把right换到middle的位置上;
二分查找就是这样的往复,你,学废了吗(狗头),没有的话就来看看几道题叭~
难度简单416
给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
。
示例 1:
输入:nums
= [-1,0,3,5,9,12],target
= 9 输出: 4 解释: 9 出现在nums
中并且下标为 4
示例 2:
输入:nums
= [-1,0,3,5,9,12],target
= 2 输出: -1 解释: 2 不存在nums
中因此返回 -1;
思想:从两边入手,找到两边的最中间,让其与目标值比较即可;不懂的话用纸笔模拟一下就好了。
TIPS:只要是属于二分查找的题目,大框架基本都一致,看后面的两道二分查找就知道啦!
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int middle = left + ((right-left)/2);
if(nums[middle]>target)
right=middle-1;
else if(nums[middle]<target)
left=middle+1;
else return middle;
}
return -1;
}
};
难度简单410
你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。
假设你有 n
个版本 [1, 2, ..., n]
,你想找出导致之后所有版本出错的第一个错误的版本。
你可以通过调用 bool isBadVersion(version)
接口来判断版本号 version
是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。
示例 1:
输入:n = 5, bad = 4 输出:4 解释:调用 isBadVersion(3) -> false 调用 isBadVersion(5) -> true 调用 isBadVersion(4) -> true
所以,4 是第一个错误的版本。
示例 2:
输入:n = 1, bad = 1 输出:1
思想:本质上还是二分查找,所以框架还是一样滴!!!难点就在于,你要发现它是二分查找!!
class Solution {
public:
int firstBadVersion(int n) {
int low=1;
int hight=n;
while(low<hight){
int middle = low + (hight-low)/2;
if(isBadVersion(middle)){
hight=middle;
}
else{
low=middle+1;
}
}
return hight;
}
};
难度简单1074
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n)
的算法。
示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2
示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1
示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4
示例 4:
输入: nums = [1,3,5,6], target = 0 输出: 0
示例 5:
输入: nums = [1], target = 0 输出: 0
思想:因为是排序数组+找到目标值,其实就=二分查找,看着很复杂但其实本质还是二分查找而已。要注意区分情况!
// 分别处理如下四种情况
// 目标值在数组所有元素之前 [0, -1]
// 目标值等于数组中某一个元素 return middle;
// 目标值插入数组中的位置 [left, right],return right + 1
// 目标值在数组所有元素之后的情况 [left, right], return right + 1
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n - 1;
while (left <= right) {
int middle = left + ((right - left) / 2);//以上感觉就是固定框架;
if (nums[middle] > target) {
right = middle - 1;
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
return right + 1;
}
};
OK啦!二分查找,你,学费了嘛(狗头)