二分查找法
这是二分查找有关链接:
视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili
题目如下:力扣
对于这一道题,我的第一想法就是直接一个for循环
for(i=0;i<nums.size();i++)
再加上if判断,如果有就直接return i,如果i一直加到了nums.size(),就说明都没有,直接返回-1;
然而,由于题目已知,数组元素是按照升序排列,所以就有了新的做法——二分查找法。
对于二分查找法,我自己的理解是,通过设置两个下标(left、right),分别作为区间的两个边界,在通过区间的nums(mid)来进行缩小区间
二分查找其实就是一个通过nums[mid]与target比较来缩小区间的过程,直到nums[mid]等于target
其实这个原理还是比较容易理解的,但很多同学一看就会,一做就废,主要是因为对于区间类型的选择和边界处理之间理解不到位
二分查找法对于区间的选择主要有两种,分别是左闭右闭和左闭右开,两种区间的选择也会导致边界的处理不同
左闭右闭
代码如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;//区间的左边界
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;//防止整形范围溢出
if(nums[mid]<target)//说明target不可能在左半部分
{
left=mid+1;//将左边界定在mid后边一个
}
else if(nums[mid]>target)//说明target不可能在右半部分
{
right=mid-1;//将有边界定在mid前边一个
}
else
{
return mid;
}
}
return -1;
}
};
左闭右开代码如下:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;//区间的左边界
int right=nums.size();
while(left<right)
{
int mid=left+(right-left)/2;//防止整形范围溢出
if(nums[mid]<target)//说明target不可能在左半部分
{
left=mid+1;//将左边界定在mid后边一个
}
else if(nums[mid]>target)//说明target不可能在右半部分
{
right=mid;//将有边界定在mid前边一个
}
else
{
return mid;
}
}
return -1;
}
};
其实很好理解,在数学思维中,[1,1]是合法的,[1,1)是不合法的
移除数组
我一开始的想法就是纯暴力移除,两层for循环,第一层找到移除元素,第二层实现元素的依次覆盖,代码如下:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i=0;
int n=nums.size();
int count=0;
for(i;i<n;i++)
{
if(nums[i]==val)
{
for(int j=i+1;j<n;j++)
{
nums[j-1]=nums[j];
}
i--;
n--;
}
}
return n;
}
};
然而两个for循环,时间复杂度较大
我们还可以采用双指针法。
代码如下:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow=0;//慢指针定位
int n=nums.size();
for(int fast=0;fast<n;fast++) //快指针指向所需要的元素
{
if(nums[fast]!=val)
{
nums[slow]=nums[fast];
slow++;
}
}
return slow;
}
};
其实,这道题本身并没有使用指针,而是用下标代替指针,而思想正是双指针的思想。
快指针用来寻找自己不移除的数字。
慢指针用来定位,每当慢指针指向的元素被快指针覆盖,慢指针就会进一位。
问题:
为什么写成int mid=left+(right-left)/2而不是int mid=(left+right)/2-------(防止溢出)
边界处理
双指针法,双指针的运动规则和意义。
算法训练营第一天!!耗时4个小时。打卡完成!!!