优选算法专题3:二分查找

二分查找

目录

二分查找

试题一:二分查找

算法原理

代码编写

试题2:在排序数组中查找元素第一个和最后一个位置

算法原理

代码编写

试题3:搜索插入位置

算法原理

代码编写

试题4:x的平方根

算法原理

代码编写

试题5:山峰数组的峰顶

算法原理

代码编写

试题6:寻找峰值

算法原理

代码编写

试题7:寻找旋转排序数组中的最小值

算法原理

代码编写

试题8:点名

算法原理

代码编写


试题一:二分查找

算法原理

解法一:暴力枚举

从左往右遍历一遍数组

时间复杂度:O(N)

解法二:二分查找算法

利用二段性,实现二分查找

循环结束的条件为left > right

二分查找算法的效率:O(logN)

朴素二分模板

代码编写

  • 个人版本
cpp 复制代码
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;
    }
};
  • 标准版本
cpp 复制代码
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;
    }
};

试题2:在排序数组中查找元素第一个和最后一个位置

算法原理

解法一:暴力查找

从左往右遍历

时间复杂度:O(N)

解法二:二分算法

朴素二分只能找到这个数值,但是并不知道起始位置与终止位置

所以需要利用二段性进行优化

查找区间的左端点

查找区间的右端点

代码编写

  • 个人版本
cpp 复制代码
class Solution
{
public:
    vector<int> searchRange(vector<int>& nums, int target)
    {
        vector<int> ret;
        if (nums.size() == 0)
        {
            ret = {-1, -1};
            return ret;
        }
        //找左边界
        int first_left = 0;
        int first_right = nums.size() - 1;
        while (first_left < first_right)
        {
            int first_mid = first_left + (first_right - first_left) / 2;
            if (nums[first_mid] < target)
            {
                first_left = first_mid + 1;
            }
            else
            {
                first_right = first_mid;
            }
        }
        //判断target是否不存在
        if (nums[first_left] != target)
        {
            ret = {-1, -1};
            return ret;
        }

        //找右边界
        int last_left = 0;
        int last_right = nums.size() - 1;
        while (last_left < last_right)
        {
            int last_mid = last_left + (last_right - last_left + 1) / 2;
            if (nums[last_mid] > target)
            {
                last_right = last_mid - 1;
            }
            else
            {
                last_left = last_mid;
            }
        }
        ret = {first_left, last_left};
        return ret;
    }
};
  • 标准版本
cpp 复制代码
class Solution 
{
public:
    vector<int> searchRange(vector<int>& nums, int target) 
    {
       //处理边界情况
       if(nums.size() == 0) return {-1,-1};
       int begin = 0;
       //#1:二分左端点
       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;//标记左端点

       //#2:二分右端点
       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;
       }
       return {begin,right};
    }
};

试题3:搜索插入位置

算法原理

查找区间左端点

代码编写

  • 个人版本
cpp 复制代码
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
            {
                right = mid;
            }
        }
        if(target > nums[nums.size() - 1])
        {
            return nums.size();
        }
        return left;
    }
};
  • 标准版本
cpp 复制代码
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;
    }
};

试题4:x的平方根

算法原理

查找区间右端点

代码编写

  • 个人版本
cpp 复制代码
class Solution 
{
public:
    int mySqrt(int x) 
    {
        if(x == 0)
        {
            return 0;
        }
        long long right = x;
        long long left = 0;
        while(left < right)
        {
            long long mid = left + (right - left + 1) / 2;
            if(mid * mid > x)
            {
                right = mid - 1;
            }
            else
            {
                left = mid;
            }
        }
        return right;
    }
};
  • 标准版本
cpp 复制代码
class Solution 
{
public:
    int mySqrt(int x) 
    {
        if(x < 1) return 0;//处理边界情况
        long long left = 1,right = x;
        while(left < right)
        {
            long long mid = left + (right - left + 1) / 2;//防溢出
            if(mid * mid <= x) left = mid;
            else right = mid - 1; 
        }
        return left;
    }
};

试题5:山峰数组的峰顶

算法原理

解法一:暴力枚举

时间复杂度:O(N)

解法二:二分查找

利用二段性,查找区间右端点

代码编写

  • 个人版本
cpp 复制代码
class Solution 
{
public:
    int peakIndexInMountainArray(vector<int>& arr) 
    {
        int left = 0;
        int right = arr.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            if(arr[mid] > arr[mid - 1])
            {
                left = mid;
            }
            else
            {
                right = mid - 1;
            }
        }   
        return left;
    }
};
  • 标准版本
cpp 复制代码
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;
    }
};

试题6:寻找峰值

算法原理

解法一:暴力解法

从第一个位置一直往后走,分情况讨论

时间复杂度:O(N)

解法二:二分查找

在严格无序的情况下,如果发现二段性,依旧能够使用二分算法

代码编写

  • 个人版本
cpp 复制代码
class Solution 
{
public:
    int findPeakElement(vector<int>& nums) 
    {
        int left = 0;
        int right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[mid + 1])
            {
                right = mid;
            }
            else
            {
                left = mid + 1;
            }
        }
        return left;
    }
};
  • 标准版本
cpp 复制代码
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]) right = mid;
            else left = mid + 1;
        }
        return left;
    }
};

试题7:寻找旋转排序数组中的最小值

算法原理

解法一:暴力查找最小值

时间复杂度:O(N)

解法二:二分查找算法

代码编写

  • 个人版本
cpp 复制代码
class Solution 
{
public:
    int findMin(vector<int>& nums) 
    {
        int left = 0;
        int right = nums.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[nums.size() - 1])
            {
                left = mid + 1;
            }
            else
            {
                right = mid;
            }
        }
        return nums[left];
    }
};
  • 标准版本
cpp 复制代码
class Solution 
{
public:
    int findMin(vector<int>& nums) 
    {
        int left = 0,right = nums.size() - 1;
        int x = nums[right];
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > x) left = mid + 1;
            else right = mid;
        }
        return nums[left];
    }
};

试题8:点名

算法原理

O(N)解法:

哈希表

直接遍历

位运算

高斯求和

O(logN)解法:二分查找

代码编写

  • 个人版本
cpp 复制代码
class Solution 
{
public:
    int takeAttendance(vector<int>& records) 
    {
        int left = 0;
        int right = records.size() - 1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(records[mid] == mid)
            {
                left = mid + 1;
            }
            else
            {
                right = mid;
            }
        }
        return records[left] == left ? records.size() : left;
    }
};
  • 标准版本
cpp 复制代码
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;
       }
       return records[left] == left ? left + 1 : left;
    }
};
相关推荐
longlongzihan5 分钟前
C++ 常用数据结构速查:vector、stack、queue、list、树、图、哈希表等声明与核心操作
数据结构·c++·list
程序 代码狂人13 分钟前
数据开发面试【问答完整版|带深挖追问 + 扩展回答】
面试·职场和发展
思茂信息17 分钟前
CST技术案例:加载正弦曲线的平面螺旋天线仿真研究
算法·平面·emc·cst·电磁仿真·仿真辐射
嫂子开门我是_我哥20 分钟前
敏感性分析
算法·机器学习·论文笔记
别动我齐刘海24 分钟前
实时控制学习2
linux·c++·人工智能·学习·算法
有Li33 分钟前
EEG脑电图数据处理基础
人工智能·算法·机器学习·语言模型·医学生
XMXFS44 分钟前
小红书推荐算法底层逻辑解析:用数据思维做内容优化
python·算法·新媒体运营·推荐算法
0+1111 小时前
算法 --栈
算法·leetcode
鶴哥只手遮天1 小时前
Gmsh 源码深度解析-第 2 章 几何内核
算法·开源
鶴哥只手遮天1 小时前
Gmsh 源码深度解析-第 9 章 后处理与插件体系
算法·开源