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

【算法题】三道题理解算法思想——二分查找算法

作者头像
小皮侠
发布2024-04-08 20:49:06
690
发布2024-04-08 20:49:06
举报

二分查找算法

本篇文章中会带大家从零基础到学会利用二分查找的思想解决算法题,我从力扣上筛选了三道题,难度由浅到深,会附上题目链接以及算法原理和解题代码,希望大家能坚持看完,绝对能有收获,大家有更好的思路也欢迎大家在评论区交流啊!

文章顺序:

题目链接=》算法原理=》代码呈现

思想总结:

在某种判断条件下将区间⼀分为⼆,然后舍去其中⼀个区间,然后再另⼀个区间内查找。 需要注意的是二分查找算法不是只可以在有序的的数组中使用,只要一组数据在某个值的前后性质具有单调性都可以使用,也就是具有二段性。

1.二分查找

题目链接:

https://leetcode.cn/problems/binary-search/

算法思路:

。定义 left , right 指针,分别指向数组的左右区间。

。找到待查找区间的中间点 mid ,找到之后分三种情况讨论:

  1. arr[mid] == target 说明正好找到,返回 mid 的值;
  2. arr[mid] > target 说明 [mid, right] 这段区间都是⼤于 target 的,因此舍去右边区间,在左边 [left, mid -1] 的区间继续查找,即让 right = mid -1 ,然后重复 2 过程;
  3. arr[mid] < target 说明 [left, mid] 这段区间的值都是⼩于 target 的,因此舍去左边区间,在右边 [mid + 1, right] 区间继续查找,即让 left = mid +1 ,然后重复 2 过程;

。当 left 与 right 错开时,说明整个区间都没有这个数,返回 -1 。

代码呈现:

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

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

题目链接:

https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/description/

算法思路:

⽤的还是⼆分思想,就是根据数据的性质,在某种判断条件下将区间⼀分为⼆,然后舍去其中⼀个区间,然后再另⼀个区间内查找;

为⽅便叙述,⽤ x 表⽰该元素, resLeft 表⽰左边界, resRight 表⽰右边界。

寻找左边界思路:

1. 寻找左边界:

。 我们注意到以左边界划分的两个区间的特点:

▪ 左边区间 [left, resLeft - 1] 都是⼩于 x 的;

▪ 右边区间(包括左边界) [resLeft, right] 都是⼤于等于 x 的;

2. 因此,关于 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] 上寻找左边界;

3. 由此,就可以通过⼆分,来快速寻找左边界;

注意:这⾥找中间元素需要向下取整。

因为后续移动左右指针的时候:

  • 左指针: left = mid + 1 ,是会向后移动的,因此区间是会缩⼩的;
  • 右指针: right = mid ,可能会原地踏步(⽐如:如果向上取整的话,如果剩下 1,2 两个元素, left == 1 , right == 2 , mid == 2 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)。

因此⼀定要注意,当 right = mid 的时候,要向下取整。

寻找右边界思路:

1. 寻右左边界:

◦ ⽤ resRight 表⽰右边界;

◦ 我们注意到右边界的特点:

▪ 左边区间 (包括右边界) [left, resRight] 都是⼩于等于 x 的;

▪ 右边区间 [resRight+ 1, right] 都是⼤于 x 的;

2. 因此,关于 mid 的落点,我们可以分为下⾯两种情况:

◦ 当我们的 mid 落在 [left, resRight] 区间的时候,说明 [left, mid - 1]( mid 不可以舍去,因为有可能是最终结果) 都是可以舍去的,此时更新 left 到 mid的位置;

◦ 当mid落在 [resRight+ 1, right] 的区间的时候,说明 [mid, right] 内的元素是可以舍去的,此时更新 right 到 mid - 1 的位置;

3. 由此,就可以通过⼆分,来快速寻找右边界;

注意:这⾥找中间元素需要向上取整。

因为后续移动左右指针的时候:

  • 左指针: left = mid ,可能会原地踏步(⽐如:如果向下取整的话,如果剩下 1,2 两个元素, left== 1, right == 2,mid == 1 。更新区间之后, left,right,mid 的值没有改变,就会陷⼊死循环)。
  • 右指针: right = mid - 1 ,是会向前移动的,因此区间是会缩⼩的;

因此⼀定要注意,当 right = mid 的时候,要向下取整。

代码呈现:

代码语言:javascript
复制
class Solution {
    public int[] searchRange(int[] nums, int target) {
      int n=nums.length;
      int left=0;
      int right=n-1;
      int[] arr=new int[2];
      arr[0]=-1;
      arr[1]=-1;
      while(left<right){
          int mid=left+(right-left)/2;
          if(nums[mid]<target){
              left=mid+1;
          }else{
              right=mid;
          }
      }
      if(left==right&&nums[right]==target) arr[0]=left;
      left=0;
      right=n-1;
      while(left<right){
          int mid=left+(right-left+1)/2;
          if(nums[mid]<=target){
              left=mid;
          }else{
              right=mid-1;
          }
      }
      if(left==right&&nums[left]==target) arr[1]=left;
      return arr;
    }
}

3.寻找峰值

题目链接:

https://leetcode.cn/problems/find-peak-element/description/

算法思路:

寻找⼆段性:

任取⼀个点 i ,与下⼀个点 i + 1 ,会有如下两种情况:

  • arr[i] > arr[i + 1] :此时「左侧区域」⼀定会存在⼭峰(因为最左侧是负⽆穷),那么我们可以去左侧去寻找结果;
  • arr[i] < arr[i + 1] :此时「右侧区域」⼀定会存在⼭峰(因为最右侧是负⽆穷),那么我们可以去右侧去寻找结果。

当我们找到「⼆段性」的时候,就可以尝试⽤「⼆分查找」算法来解决问题。

代码呈现:

代码语言:javascript
复制
class Solution {
    public int findPeakElement(int[] nums) {
         int n=nums.length;
         int left=0;
         int right=n-1;
         while(left<right){
             int mid=left+(right-left)/2;
             if(nums[mid]<nums[mid+1]){
                 left=mid+1;
             }else{
                 right=mid;
             }
         }
         return left;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-06,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二分查找算法
    • 1.二分查找
      • 2.在排序数组中查找元素的第一个和最后一个位置
        • 3.寻找峰值
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档