前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【算法】二分算法题

【算法】二分算法题

作者头像
zxctscl
发布2024-04-10 09:59:23
740
发布2024-04-10 09:59:23
举报
文章被收录于专栏:zxctscl个人专栏zxctscl个人专栏

1. 704. 二分查找

1.1 分析

用两个指针,一个在前面left,一个在后面right,求出中间值half,与目标值比较。如果相等,就直接返回下标;如果小于目标值,说明值在后面的区间,此时更新一下left=half+1;如果如果大于目标值,说明值在前面的区间,此时更新一下right=half-1。如果区间都找完没有,就返回-1。

1.2 代码

代码语言:javascript
复制
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
  
        while(left<=right)
        {
            int half=left+(right-left)/2;
            if(nums[half]<target)
            {
                left=half+1;
            }
            else if(nums[half]>target)
            {
                right=half-1;
            }
            else  return half;
        }
       return -1;
    }
};

2. 34. 在排序数组中查找元素的第一个和最后一个位置

2.1 分析

寻找左边界: 我们注意到以左边界划分的两个区间的特点: 左边区间 [left, resLeft - 1] 都是小于x 的;右边区间(包括左边界) [resLeft, right] 都是等于等于 x 的;因此,关于 mid 的落点,我们可以分为下面两种情况:◦ 当我们的 mid 落在 [left, resLeft - 1] 区间的时候,也就是 arr[mid] < target 。说明 [left, mid] 都是可以舍去的,此时更新 left 到 mid + 1 的位置,继续在 [mid + 1, right] 上寻找左边界;当 mid 落在 [resLeft, right] 的区间的时候,也就是 arr[mid] >= target 。 说明 [mid + 1, right] (因为 mid 可能是最终结果,不能舍去)是可以舍去的,此时更新 right 到 mid 的位置,继续在 [left, mid] 上寻找左边界; 注意:这里找中间元素需要向下取整。 因为后续移动左右指针的时候: • 左指针: left = mid + 1 ,是会向后移动的,因此区间是会缩⼩的; • 右指针: right = mid ,可能会原地踏步(比如:如果向上取整的话,如果剩下 1,2 两个元素, left == 1 , right == 2mid == 2 。更新区间之后, left,right,mid 的值没有改变,就会陷入死循环)。因此⼀定要注意,当 right = mid 的时候,要向下取整。

寻找右边界思路: 寻右左边界: ⽤ Right 表示右边界; 我们注意到右边界的特点: 左边区间 (包括右边界) [left, Right] 都是小于等于 x 的;右边区间 [resRight+ 1, right] 都是大于 x 的;因此,关于 mid 的落点,我们可以分为下面两种情况:当我们的 mid 落在 [left, Right] 区间的时候,说明 [left, mid - 1]( mid 不可以舍去,因为有可能是最终结果) 都是可以舍去的,此时更新 left 到 mid的位置; 当 mid 落在 [Right+ 1, right] 的区间的时候,说明 [mid, right] 内的元素是可以舍去的,此时更新 right 到 mid - 1 的位置; 注意:这⾥找中间元素需要向上取整。 因为后续移动左右指针的时候: • 左指针: left = mid ,可能会原地踏步(比如:如果向下取整的话,如果剩下 1,2 两个元素, left == 1right == 2mid == 1 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)。 • 右指针: right = mid - 1 ,是会向前移动的,因此区间是会缩小的; 因此⼀定要注意,当 right = mid 的时候,要向下取整。

2.2 代码

代码语言:javascript
复制
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. 35. 搜索插入位置

3.1 分析

利用二分算法的特性,将区间分为两部分,一部分是小于目标值的,那么这个区间就不考虑了;另一部分是等于等于目标值的,如果等于目标值那么就直接返回这个下标,如果大于目标值,那么这个值也是第一个比目标值大的数,这个位置的数之前就得插入目标值,返回的也是这个下标。

3.2 代码

代码语言:javascript
复制
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 right + 1;
    return left;
    }
};

4. 852. 山脉数组的峰顶索引

4.1 分析

题目给的元素特性很明显,在某一个位置之前的元素都是呈现上升趋势,在它之后都会呈现下降趋势。按照这个特性可以将数组分为两部分:1.mid的值小于mid-1,那么最大值就在前面的区间,那么就更新一下right=mid-1;2.mid的值大于等于mid-1,那么最大值就在后面的区间,更新一下left=mid。最终就找到当循环条件返回left就可以。

4.2 代码

代码语言:javascript
复制
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;
    }
};

5. 153. 寻找旋转排序数组中的最小值

5.1 分析

根据题目所给的特性,可以将数组分为两段区间,都是明显呈现递增。第二段区间所有的值都小于第一段。选择最后最后一个值为参考值。如果在mid大于最后一个值,说明最小值在后面的区间,更新一下left=mid+1;如果如果在mid小于等于最后一个值,那么就更新一下right=mid。

5.2 代码

代码语言:javascript
复制
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];
    }
};

6. 二分算法模板

定义两个指针,然后找符合条件的情况按下面的模板走。 填上对应的if表达式,返回题目要求的值即可。

有问题请指出,大家一起进步!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 704. 二分查找
    • 1.1 分析
      • 1.2 代码
      • 2. 34. 在排序数组中查找元素的第一个和最后一个位置
        • 2.1 分析
          • 2.2 代码
          • 3. 35. 搜索插入位置
            • 3.1 分析
              • 3.2 代码
              • 4. 852. 山脉数组的峰顶索引
                • 4.1 分析
                  • 4.2 代码
                  • 5. 153. 寻找旋转排序数组中的最小值
                    • 5.1 分析
                      • 5.2 代码
                      • 6. 二分算法模板
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档