飞道的博客

力扣算法篇:二分查找

244人阅读  评论(0)

二分查找1.0


自己实现一个二分查找:

class Solution {
   
public:
    int search(vector<int>& nums, int target) {
   
        //二分查找
        int left = 0;
        int right = nums.size()-1;
        while(left<=right){
   
            //为防止数据太大溢出 可使用 mid = 左+(右-左)/2
            int mid = (left+right)/2;
            if(nums[mid]==target){
   
                return mid;
            }
            //定左侧还是右侧
            if(target<nums[mid]){
   
                //更改右侧值
                right = mid-1;
            }else{
   
                //更改左侧值
                left = mid+1;
            }
        }
        //出来了 没找到
        return -1;
    }
};

模板

模板一:寻找一个数

int binarySearch(vector<int>& nums, int target){
   
  if(nums.size() == 0)
    return -1;
  int left = 0, right = nums.size() - 1;
  while(left <= right){
   
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){
    return mid; }
    else if(nums[mid] < target) {
    left = mid + 1; }
    else {
    right = mid - 1; }
  }
  return -1;
}

关键点:

练习-x的平方根


题解:注意溢出 找不到时 最后判断结果是mid还是mid-1

class Solution {
   
public:
    int mySqrt(int x) {
   
        //考虑x为0的情况
        if(x == 0){
   
            return 0;
        }
        //求某数的平方根 不为整数时舍去小数 采用二分查找 从1-n
        int left = 1;
        int right = x;
        int mid = 0;
        while(left<=right){
   
            //计算mid
            mid = left+(right-left)/2;
            long mid_2 = (long)mid*mid;
            if(mid_2 == x){
   
                return mid;
            }
            //定左侧还是右侧
            if(mid_2<x){
   
                left = mid+1;
            }else{
   
                right = mid-1;
            }
        }
        return (long)mid*mid<=x ? mid:mid-1;
    }
};

练习-猜数字大小


题解:防溢出 mid = left+(right-left)/2;

/** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is lower than the guess number
 *			      1 if num is higher than the guess number
 *               otherwise return 0
 * int guess(int num);
 */
class Solution {
   
public:
    int guessNumber(int n) {
   
       //二分查找
       int left = 1;
       int right = n;
       while(left<=right){
   
           int mid = left+(right-left)/2;
           int temp = guess(mid);
           if( temp == 0){
   
               //猜对了
               return mid;
           }
           //没猜对
           if(temp == -1){
   
               //pick<mid
               right = mid-1;
           }else{
   
               //pick>mid
               left = mid+1;
           }
       }
       //总能找到滴
        return 0;
    }
};

练习-搜索旋转排序数组

题解

class Solution {
   
public:
    int binarysearch2(vector<int>& nums, int left,int right, int target) {
   
        //二分查找
        while(left<=right){
   
            //为防止数据太大溢出 可使用 mid = 左+(右-左)/2
            int mid = (left+right)/2;
            if(nums[mid]==target){
   
                return mid;
            }
            //定左侧还是右侧
            if(target<nums[mid]){
   
                //更改右侧值
                right = mid-1;
            }else{
   
                //更改左侧值
                left = mid+1;
            }
        }
        //出来了 没找到
        return -1;
    }
    int search(vector<int>& nums, int target) {
   
        //在不排序的情况下使用二分查找找出目标值
        //该数组原来有序 则旋转后 两区间部分有序(升序) 找出断点 断点 前>后 或者是以0为旋转点 本身有序
        int trancenter = 0; 
        for(int i = 1;i<=nums.size()-1;i++){
   
            if(nums[i]<nums[i-1]){
   
                //断点为i
                trancenter = i-1;
                break;
            }
        }
        //在断点的左右两侧使用二分查找
        int result = binarysearch2(nums,0,trancenter,target);
        if(result != -1){
   
            return result;
        }
        result = binarysearch2(nums,trancenter+1,nums.size()-1,target);
        if(result != -1){
   
            return result;
        }
        return -1;
    }
};

进阶

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)/2;
            if(nums[mid] == target){
   
                return mid;
            }
            //left到mid是升序
            if(nums[left]<=nums[mid]){
   
                //看target在哪 left和mid之间
                if(nums[left]<=target && target<nums[mid]){
   
                    right = mid-1;
                }else{
   //mid和right之间
                    left = mid+1;
                }
            }else{
   
                //升序段在mid左边  nums[left]>nums[mid]
                //mid右边是升序段 mid到right 看target在哪 
                //mid和right之间
                if(nums[mid]<target&&target<=nums[right]){
   
                    left = mid+1;
                }else{
   //left和mid之间
                    right = mid-1;
                }
            }
        }
        return -1;
    }
};

模板二 寻找左侧边界

int binarySearch(vector<int>& nums, int target){
   
  if(nums.size() == 0)
    return -1;

  int left = 0, right = nums.size();
  while(left < right){
   
    // Prevent (left + right) overflow
    int mid = left + (right - left) / 2;
    if(nums[mid] == target){
    return mid; }
    else if(nums[mid] < target) {
    left = mid + 1; }
    else {
    right = mid; }
  }

  // Post-processing:
  // End Condition: left == right
  if(left != nums.size() && nums[left] == target) return left;
  return -1;
}


注意到初始条件是left=0,right=n,即左闭右开区间。

练习题-第一个错误的版本


题解

// The API isBadVersion is defined for you.
// bool isBadVersion(int version);

class Solution {
   
public:
    int firstBadVersion(int n) {
   
        //寻找第一个错误的版本 二分法
        int left = 0;
        int right = n;
        while(left<right){
   
            //计算中间值
            int mid = left+(right-left)/2;
            //判断该产品是否为错误版本
            if(isBadVersion(mid)){
   
                //该版本为错误版本 right定位到mid
                right = mid;
            }else{
   
                //不是错误版本 left定位到mid+1
                left = mid+1;
            }
        }
        //出来的条件是left =right left 意为最左边的错误版本 即第一个错误版本
        return left;
    }
};

转载:https://blog.csdn.net/qq_22494201/article/details/115796294
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场