1.经典的不能在经典的二分查找(难度⭐)
Leetcode链接:704. 二分查找
1.1题目描述:
这是一道非常典型的二分查找算法题目,可以说所有要学习二分查找算法的人都必须掌握这道题。题目要求很简单,就是在一个有序数组中查找目标值target。这道题是二分查找算法的入门题和模版题,没有掌握这道题就无法开始学习更复杂的二分查找算法题目。所以这道题对于二分查找算法的理解和掌握非常关键和必要。
1.2代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
int mid;
while(left <= right)
{
mid = (left + right)/2;
if(nums[mid]>target)
{
right = mid - 1;
}
else if(nums[mid]<target)
{
left = mid + 1;
}
else
{
return mid;
}
}
return -1;
}
};
通过这道二分查找的典型题,我对二分查找算法的理解更进一步:
我对二分查找的区间划分有了更深的理解:
- 当mid位置的值小于target时,证明左区间[left, mid-1]都不可能存在target,所以左区间变为[mid+1, right]。
- 当mid位置的值大于target时,证明右区间[mid+1, right]都不可能存在target,所以右区间变为[left, mid-1]。
- 当mid位置的值等于target时,就找到了目标值。
我理解到二分查找的本质就是通过比较中间mid值与target的值,可以排除一半的搜索区间,使搜索范围越来越小,直到找到target。
通过这道题我对二分查找算法模板有了更加熟练的掌握,可以应用到其他二分查找题目中去。
2.在排序数组中查找元素的第一个和最后一个位置(难度⭐⭐)
Leetcode链接:34. 在排序数组中查找元素的第一个和最后一个位置
2.1题目描述:
2.2代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1, begin = -1, end = -1, mid;
//找到区间左边界
while(left<=right)
{
mid = (left + right)/2;
if(nums[mid] > target)
{
right = mid - 1;
}
else if(nums[mid] < target)
{
left = mid + 1;
}
else
{
begin = mid;
right--;//right区间左移,使得mid左移,直到到达左区间边界,此时right正好和left重合
}
}
left = 0, right = nums.size() - 1;
//找到区间有边界
while(left<=right)
{
mid = (left + right)/2;
if(nums[mid] > target)
{
right = mid - 1;
}
else if(nums[mid] < target)
{
left = mid + 1;
}
else
{
end = mid;
left++;//left区间右移,使得mid右移,直到到达又区间边界,此时left正好和right重合
}
}
return {begin,end};
}
};
这道题的大思路和上面的题并没有太大区别,只是为了找到左右区间,需要两次二分查找
具体来说,在求左右区间边界时,处理mid==target的情况需要进行特别考虑:
- 求左区间边界时,需要在记录begin索引后,继续将right索引左移,使得mid向左逼近,直到不等于target时才能锁定左区间边界。
- 求右区间边界时,需要在记录end索引后,继续将left索引右移,使得mid向右逼近,直到不等于target时才能锁定右区间边界。
这种细微的逻辑调整体现了二分查找的灵活性,在保持模板框架不变的情况下,通过简单逻辑修改就可应对新的问题。
总结:
二分查找有一定的模板,灵活运用才能解决更多问题~
我们再接再厉,慢慢攻破算法大门!~
祝你快乐刷题每一天~