算法思想总结:二分查找算法

简介: 算法思想总结:二分查找算法

                                            创作不易,感谢三连!!

一、二分查找算法思路总结

大家先看总结,然后再根据后面的题型去慢慢领悟

二、二分查找(easy)

. - 力扣(LeetCode)二分查找

思路:(模版1)正常的二分查找策略

class Solution {
public:
    int search(vector<int>& nums, int target)
    {
        int left=0,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;
    }
};

三、在排序数组中查找元素的第一个位置和最后一个位置

. - 力扣(LeetCode)在排序数组中查找元素的第一个位置和最后一个位置

要注意示例3提到的边界情况!!

思路:找第一个,用左区间端点查找(模版2),找最后一个,用右端点区间查找(模版3)

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target)
    {
        if(nums.size()==0)  return {-1,-1};//处理边界情况,否则会越界
        int begin=0;
        //区间左端点
           int left=0,right=nums.size()-1;
           while(left<right)
          {
            int mid=left+(right-left)/2;
            if(nums[mid]<target) left=mid+1;
            else right=mid;//最后会落在区间的左端点
          }
          if(nums[left]!=target) return{-1,-1};//找不到
          else begin=left;
        //区间右端点
          right=nums.size()-1;
           while(left<right)
          {
            int mid=left+(right-left+1)/2;
            if(nums[mid]<=target) left=mid;//最后会落在区间的右端点
            else right=mid-1;
          }
        return {begin,right};//此时至少有一个左端点,所以不可能找不到。
    }
};

四、x的平方根

. - 力扣(LeetCode)x的平方根

思路:右端区间二分查找法

class Solution {
public:
    int mySqrt(int x) 
    {
        if(x<1) return 0;//处理边界情况
        int left=1,right=x/2;
        while(left<right)
        {
            long long mid=left+(right-left+1)/2;
            if(mid*mid>x) right=mid-1;
            else  left=mid;
        }
        return left;
    }
};

五、搜索插入位置

. - 力扣(LeetCode)搜索插入位置

思路1:左端区间查找

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) 
    {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]<target) left=mid+1;
            else right=mid;
        }
        if(nums[left]<target) return left+1;
        return left;
    }
};

思路2:右端区间查找(有特殊情况,比如正好是和targe相等且只有一个元素

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) 
    {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left+1)/2;
            if(nums[mid]<target) left=mid;
            else right=mid-1;
        }
        //右端区间要考虑边界情况(特殊情况,只有一个元素且正好等于target)
        if(nums[left]>=target) return left;
        return left+1;
    }
};

六、山峰数组峰顶的索引

. - 力扣(LeetCode)山峰数组峰顶的索引

本题特别的就是不再是升序,而是去找二段性的规律

思路1:左端区间查找

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr)
    {
          int left=1,right=arr.size()-2;
          while(left<right)
          {
            int mid=left+(right-left)/2;
             if(arr[mid]<arr[mid+1])  left=mid+1;
             else right=mid;   
          }
          return left;
    }
};

思路2:右端区间查找

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr)
    {
          int left=1,right=arr.size()-2;
          while(left<right)
          {
            int mid=left+(right-left+1)/2;
             if(arr[mid]>=arr[mid-1])  left=mid;
             else right=mid-1;   
          }
          return left;
    }
};

七、寻找峰值

. - 力扣(LeetCode)寻找峰值

左区间端点法:

class Solution {
public:
    int findPeakElement(vector<int>& nums) 
    {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]<nums[mid+1]) left=mid+1;
            else right=mid;
        }
        return right;
    }
};

右区间端点法:

class Solution {
public:
    int findPeakElement(vector<int>& nums) 
    {
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int mid=left+(right-left+1)/2;
            if(nums[mid]>=nums[mid-1]) left=mid;
            else right=mid-1;
        }
        return right;
    }
};

八、点名

. - 力扣(LeetCode)点名

左区间端点法

class Solution {
public:
    int takeAttendance(vector<int>& records) 
    {
           int left=0,right=records.size()-1;
           while(left<right)
           {
            int mid=left+(right-left)/2;
            if(records[mid]==mid)   left=mid+1;
            else  right=mid;
           }
           if(records[right]==right)  return right+1;
           else return right;
    }
};

注意:插入元素的时候要注意是否是在最右边插入!

九、 寻找旋转数组中的最小值

. - 力扣(LeetCode)寻找旋转数组中的最小值

思路:左区间端点查找法

class Solution {
public:
    int findMin(vector<int>& nums) 
    {
       int left=0,right=nums.size()-1;
        int target=nums[right];//标记一下
        while(left<right)
        {
            int mid=left+(right-left)/2;
            if(nums[mid]>target) left=mid+1;
            else right=mid;
        }
        return nums[left];
    }
};

十、二分查找规律的再总结

      二分查找的策略基本上都是去找一个数,对应的有三种模版:正常的二分查找、左区间端点查找、右区间端点查找。其中正常的二分查找局限性比较大,必须得是升序且限制条件较多,大多数情况下不符合题意。最常用的就是左区间端点(关键是left会大跳跃,且目标位置在较大值区间的左边)和右区间端点法(关键是right会大跳跃,且目标位置在较小值区间的右边)。

 

    后面有遇到相关oj题博主会继续更新的……感谢支持!!

相关文章
|
4月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
2月前
|
算法 C# 索引
C#二分查找算法
C#二分查找算法
|
2月前
|
存储 算法 C语言
【C语言】二分查找算法
【C语言】二分查找算法
|
2月前
|
消息中间件 存储 算法
一文搞懂二分查找算法!
一文搞懂二分查找算法!
121 0
|
2月前
|
算法 Java 索引
数据结构与算法学习十五:常用查找算法介绍,线性排序、二分查找(折半查找)算法、差值查找算法、斐波那契(黄金分割法)查找算法
四种常用的查找算法:顺序查找、二分查找(折半查找)、插值查找和斐波那契查找,并提供了Java语言的实现代码和测试结果。
31 0
|
4月前
|
存储 算法 Java
深入算法基础二分查找数组
文章深入学习了二分查找算法的基础,通过实战例子详细解释了算法的逻辑流程,强调了确定合法搜索边界的重要性,并提供了Java语言的代码实现。
深入算法基础二分查找数组
|
5月前
|
算法
【算法】二分查找(整数二分和浮点数二分)
算法学习——二分查找(整数二分和浮点数二分)
49 0
【算法】二分查找(整数二分和浮点数二分)
|
4月前
|
算法
【算法】二分查找——二分查找
【算法】二分查找——二分查找
|
6月前
|
存储 算法 C语言
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
二分查找算法的概念、原理、效率以及使用C语言循环和数组的简单实现
|
6月前
|
机器学习/深度学习 算法 索引
数据结构算法--1 顺序查找二分查找
**顺序查找时间复杂度为O(n)**,适合无序列表,可以通过`enumerate`或直接遍历索引来实现。**二分查找时间复杂度为O(logn)**,适用于有序列表,利用Python中`left`、`right`指针和`mid`点不断缩小搜索范围。效率上二分查找更优。