704. 二分查找
代码:
方法一
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) left=mid+1;
else if(nums[mid]>target) right=mid-1;
else return mid;
}
return -1;
}
};
方法二
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0;
int right=nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
// 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
while(left<right){
int mid=left+(right-left)/2;
if(nums[mid]<target) left=mid+1; // target 在右区间,在[middle + 1, right)中
else if(nums[mid]>target) right=mid; // target 在左区间,在[left, middle)中
else return mid;
}
return -1;
}
};
知识点:
1、mid=left+(right-left)/2保证了不会超过基本类型的所能容纳的最大值;
2、vector<int>& nums:传入为vector的引用(物理地址——嫁鸡随鸡);
vector<int> nums:传入的 vector的复制品,改动 原本的vector;
35. 搜索插入位置
力扣链接: 35. 搜索插入位置 - 力扣(LeetCode)
代码:
class Solution {
public:
int searchInsert(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) left=mid+1;
else if(nums[mid]>target) right=mid-1;
else return mid;
}
return right+1; //也可以return left
}
};
易错点:
1、当目标值不在数组中时,为什么返回right+1/left?
答:因为循环条件为left<=right,因此跳出循环后,left>right,而前一次循环中比较的是mid=left=right,若是nums[mid]<target,则nums[right]<target,left=mid+1,因此插入位置为right+1/left;若是nums[mid]>target,则nums[right]>target,right=mid-1,因此插入位置为right+1/left;
34. 在排序数组中查找元素的第一个位置和最后一个位置
力扣链接: 34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int leftborder=findleftborder(nums,target);
int rightborder=findrightborder(nums,target);
if(leftborder==-2||rightborder==-2) return {-1,-1};
else if(rightborder-leftborder>1) return {leftborder+1,rightborder-1};
else return {-1,-1};
}
private:
int findleftborder(vector<int>& nums, int target){
int leftborder=-2;
int left=0;
int right=nums.size()-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]<target) left=mid+1;
else if(nums[mid]>=target){
right=mid-1;
leftborder=right;
}
}
return leftborder;
}
int findrightborder(vector<int>& nums, int target){
int rightborder=-2;
int left=0;
int right=nums.size()-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]<=target){
left=mid+1;
rightborder=left;
}
else if(nums[mid]>target) right=mid-1;
}
return rightborder;
}
};
易错点:
1、rightborder-leftborder>1不可以加=,因为在没有找到目标的情况下rightborder-leftborder=1;
2、由于最终跳出循环的条件为left>right,因此right所代表的位置是左边界,left所代表的位置是右边界;
3、寻找左边界时,nums[mid]>=target;寻找右边界时,nums[mid]<=target;
不能忘记=,因为=包括了找到目标的这一情况;
4、初始化 rightborder 与 leftborder 时不能直接令这两个值为 -1,因为一开始就等于 -1 会默认没有找到这个元素。
69. x的平方根
力扣链接:69. x 的平方根 - 力扣(LeetCode)
代码:
class Solution {
public:
int mySqrt(int x) {
int left=0;
int right=x;
int ans=-1;
while(left<=right){
long mid=left+(right-left)/2;
if(mid*mid<=x){
ans=mid;
left=mid+1;
}
else if(mid*mid>x) right=mid-1;
}
return ans;
}
};
思路:
1、由于平方根始终小于数字本身,因此可以将[0,x]看成一个数组,并在此范围内找寻其平方根;
2、由于保留整数部分, 即当mid的平方小于等于x的时都有可能是所求的值。
易错点:
1、mid需要为long(长整形);
2、mid在二分法中是在while中定义的,不可直接返回,需要额外定义一个参数ans进行传递;
367. 有效的完全平方数
力扣链接: 367. 有效的完全平方数 - 力扣(LeetCode)
代码:
class Solution {
public:
bool isPerfectSquare(int num) {
int left=0;
int right=num;
while(left<=right){
long mid=left+(right-left)/2;
if(mid*mid<num) left=mid+1;
else if(mid*mid>num) right=mid-1;
else return true;
}
return false;
}
};