704二分查找
一,左闭右闭[left, right]
左闭右闭,说明二者最后会出现相等的情况,不能忽视left == right的情况。
//值得注意的点
1.right = nums.size()-1;
2.while(left <= right)
3. right = middle - 1;
完整版
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0,r = nums.size()-1;
while(l <= r){
int mid = l + (r-l)/2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid - 1;
}else{
l = mid +1;
}
}
return -1;
}
};
二,左闭右开[left, right)
右开说明不会出现left == right的情况
//值得注意的点
1.right = nums.size();
2.while(left < right)
3. right = middle;
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = 0,r = nums.size();
while(l < r){
int mid = l + (r-l)/2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid;
}else{
l = mid +1;
}
}
return -1;
}
};
35.搜索插入位置
本题为标准的二分查找,左闭右闭区间返回l
因为左闭右闭区间最后的l和r是l在r的右边即l>r而本题目返回的正好是要求返回比target大的最小的那个数,因此为l,因此l为比target大的最小的那个数,r为比target小的那个最大的数
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0,r = nums.size()-1;
while(l <= r){
int mid = l + (r -l)/2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid -1;
}else{
l = mid + 1;
}
}
return l;//返回左区间
}
};
左闭右开区间最后l==r所以l和r都指向了比target大的最小的那个数,因此返回l还是r都可以
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0,r = nums.size()-1;
while(l <= r){
int mid = l + (r -l)/2;
if(nums[mid] == target){
return mid;
}else if(nums[mid] > target){
r = mid -1;
}else{
l = mid + 1;
}
}
return l;//return r;
}
};
实战中,最后返回r还是l可以自己尝试提交确定。
下面是重要的二分查找的边界控制
1.在一段重复数字中求其右边界
比如:数组[1,2,4,4,4,5]的右边界为5
使用左闭右闭区间解法,要求右边界,则在nums[mid] =target 时移动left,利用left = mid +1一直移动left就把left移动到了右边界。而left = mid +1语句是在nums[mid]<target时进行的 ,即就是在nums[mid]<=target时进行left = mid +1 操作并不断赋值给r_board即可以找到右边界r_board
int getr_board(vector<int>& nums, int target){
int l=0,r = nums.size()-1;
int r_board = -2;//右边界没被赋值
while(l<=r){
int mid = l + (r-l)/2;
if(nums[mid] > target){
r = mid-1;
}else{
l = mid + 1;
r_board = l;
}
}
return r_board;
}
同理
2.在一段重复数字中求其左边界
int getl_board(vector<int>& nums, int target){
int l=0,r = nums.size()-1;
int l_board = -2;
while(l<=r){
int mid = l + (r-l)/2;
if(nums[mid] >= target){
r = mid-1;
l_board = r;
}else{
l = mid+1;
}
}
return l_board;
}
下面的题目都用了这样的思想
34. 在排序数组中查找元素的第一个和最后一个位置
本题目分为3种情况考虑
1.target在nums数组的左/右边,即target不在nums数组的范围内
2.target在数组范围内但数组内不存在target
3.数组内存在target
class Solution {
public:
int getr_board(vector<int>& nums, int target){
int l=0,r = nums.size()-1;
int r_board = -2;
while(l<=r){
int mid = l + (r-l)/2;
if(nums[mid] > target){
r = mid-1;
}else{
l = mid+1;
r_board = l;
}
}
return r_board;
}
int getl_board(vector<int>& nums, int target){
int l=0,r = nums.size()-1;
int l_board = -2;
while(l<=r){
int mid = l + (r-l)/2;
if(nums[mid] >= target){
r = mid-1;
l_board = r;
}else{
l = mid+1;
}
}
return l_board;
}
vector<int> searchRange(vector<int>& nums, int target) {
int l_board = getl_board(nums,target);
int r_board = getr_board(nums,target);
//情况1:target在nums数组的左/右边
if(l_board == -2 || r_board == -2){
return {-1,-1};
}
//情况3:存在target
if(r_board - l_board > 1){//左右边界之差大于1说明至少有1个target在数组中
return {l_board+1,r_board-1};
}
//情况2:target在数组范围内但数组内不存在target
return {-1,-1};
}
};
69. x 的平方根
本题相当于求解k*k<=x的比k小的最大的整数
class Solution {
public:
int mySqrt(int x) {
int l = 0 , r = x, ans = -1;
while(l<=r){
int mid = l + (r-l)/2;
if((long long)mid * mid <= x){
l = mid + 1;
ans = l;
}else{
r = mid - 1;
}
}
return ans -1;
}
};
367. 有效的完全平方数
class Solution {
public:
bool isPerfectSquare(int num) {
int l = 0,r= num,ans = -1;
while(l<= r){
int mid = l + (r-l)/2;
if((long long)mid * mid <= num){
l = mid + 1;
ans = mid;
}else{
r = mid - 1;
}
}
//判断两个边界是否满足条件即可求解
if(ans * ans == num){
return true;
}
if((ans-1)*(ans-1) == num){
return true;
}
return false;
}
};