【算法系列-数组】二分查找

ops/2024/10/18 2:26:30/

算法系列-数组】二分查找

文章目录

  • 算法系列-数组】二分查找
    • 1. 算法分析
    • 2. 搜索插入位置(LeetCode 35)
      • 2.1 解题思路
      • 2.2 解题过程
      • 2.3 代码
    • 3. 在排序数组中查找元素的第一个和最后一个位置(LeetCode 34)
      • 3.1 解题思路
      • 3.2 解题过程
      • 3.3 代码
    • 4. X的平方根(LeetCode 69)
      • 4.1 解题思路
      • 4.2 代码
    • 5. 有效的完全平方数(LeetCode 367)
      • 5.1 解题思路
      • 5.2 代码

1. 算法分析

二分查找这类算法题大家并不陌生,对于它的使用方式主要有两个难点,也是最容易出错的地方,就是分不清边界值

LeetCode:二分查找

一般二分查找分为两个场景:

  • 左闭右闭区间,如:提供数组[1, 5]
  • 左闭右开区间,如:提供数组[1, 5)

对此,只需要分清楚在什么场景下使用合适的边界值就能很好的写出这类题,接下来帖上两段代码:

  1. 左闭右闭

    class Solution {public int search(int[] nums, int target) {int left = 0;int right = nums.length -1;while (left <= right) { // 这里使用 `<=` ,因为在左闭右闭区间中,left = right 是合理逻辑,对此需要加上等号int mid = left + (right - left) / 2;if (nums[mid] > target) {right = mid -1; // 因为此处 nums[mid] 不等于目标值,不需要取到mid,所以在左闭右闭区间 right = mid - 1}else if (nums[mid] < target) {left = mid + 1;}else {return mid;}}return -1;}
    }
    
  2. 左闭右开

    class Solution {public int search(int[] nums, int target) {int left = 0;int right = nums.length -1;while (left < right) { // 这里使用 `<` ,因为在左闭右开区间中,left = right 是不合理逻辑,对此无需加上等号int mid = left + (right - left) / 2;if (nums[mid] > target) {right = mid; // 因为此处 nums[mid] 不等于目标值,不需要取到mid,而右开区间不取右值,所以right = mid,假设使用 mid - 1,则此时 mid - 1 的值将不会被取到,从而产生问题}else if (nums[mid] < target) {left = mid + 1;}else {return mid;}}return -1;}
    }
    

掌握解题思路后,以下几道相同类型的题可用来练习:

2. 搜索插入位置(LeetCode 35)

【题目链接】

2.1 解题思路

二分法能够解决这个问题,最主要的是在值不存在的情况下二分法得出的mid让我们节省来再去循环遍历的过程

2.2 解题过程

二分查找流程

先定义左右下标,将mid放在循环外面创建,因为当前数组为闭区间(左闭右闭),所以while循环使用left <= right 合理(如[1,1]),之后,当中间值大于目标值时,右下标 = mid - 1;当中间值小于目标值时,right = mid + 1;当中间值等于目标值时,返回mid;

查无目标值

当循环结束还没有找到目标值时,只有三种情况:

  1. right小于0,表示目标值小于数组中的所有值,返回left(此时left = 0);
  2. left大于数组长度,表示目标值大于数组中的所有值,返回left(此时left = num.length);
  3. 以上两者都不符合表示目标值需在数组中插入,此时right一定在left的左边才能退出循环,返回left(即left的位置即是插入位置)

综上所述,查无目标值的情况返回left即可

2.3 代码

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

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

【题目链接】

3.1 解题思路

二分查找+递归实现

3.2 解题过程

这道题的难点在于数组中可能存在多个相同的目标值,我们通过二分查找找到一个目标值后还需要进行判断,找到第一个和最后一个相同的目标值的下标,对此可以通过递归的方式来解决:

在找到一个目标值后,依次向左向右查询相同值

  • 向左递归:传入数组与当前目标值下标mid,判断 mid - 1 位置的值是否与当前目标值相同,若相同则传入mid - 1继续递归,否则返回当前目标值的下标**mid,**此时的mid即目标值在数组中的第一个位置;
  • 向右递归:传入数组与当前目标值下标mid,判断 mid + 1 位置的值是否与当前目标值相同,若相同则传入mid + 1继续递归,否则返回当前目标值的下标**mid,**此时的mid即目标值在数组中的最后一个位置;

最后返回结果赋值即可

3.3 代码

class Solution {public int[] searchRange(int[] nums, int target) {int left = 0;int right = nums.length - 1;int ret[] = new int[2];ret[0] = -1;ret[1] = -1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] > target) {right = mid - 1;}else if (nums[mid] < target) {left = mid + 1;} else {ret[0] = searchLeft(nums, mid);ret[1] = searchRight(nums, mid);return ret;}}return ret;}public int searchLeft(int[] nums, int mid) {if (mid - 1 >= 0 && nums[mid - 1] == nums[mid]) {mid = searchLeft(nums,  mid - 1);}return mid;}public int searchRight(int[] nums, int mid) {if (mid + 1 < nums.length && nums[mid + 1] == nums[mid]) {mid = searchRight(nums,  mid + 1);}return mid;}
}

4. X的平方根(LeetCode 69)

【题目链接】

4.1 解题思路

因为这道题限制了我们使用api,所以可以通过二分查找的方式来解决

4.2 代码

class Solution {public int mySqrt(int x) {int left = 0;int right = x;int ret = -1;while (left <= right) {int mid = left + (right - left) / 2;if ((long) mid * mid <= x) {ret = mid;left = mid + 1;}else {right = mid - 1;}}return ret;}
}

5. 有效的完全平方数(LeetCode 367)

【题目链接】

5.1 解题思路

与上道题很相似,只是返回的结果不同了,稍微调整即可

5.2 代码

class Solution {public boolean isPerfectSquare(int num) {int left = 0;int right = num;while (left <= right) {int mid = left + (right - left) / 2;if ((long) mid * mid < num) {left = mid + 1;}else if ((long) mid * mid > num) {right = mid - 1;}else {return true;}}return false;}
}

以上便是对二分查找的介绍了!!后续还会继续分享其它算法系列内容,如果这些内容对大家有帮助的话请给一个三连关注吧💕( •̀ ω •́ )✧( •̀ ω •́ )✧✨


http://www.ppmy.cn/ops/119201.html

相关文章

testRigor测试用例模板记录

testRigor测试用例模板记录 Application Description Template Application Name Name: MySampleAppApplication Type Type: Web Application / Mobile Application / Desktop ApplicationFunctionality Overview Description: MySampleApp is an online shopping platform t…

【计算机网络】网络层详解

文章目录 一、引言二、IP 基础知识1、IP 地址2、路由3、IP报文4、IP报文的分片与重组 三、IP 属于面向无连接型四、IP协议相关技术1、DNS2、ICMP3、NAT技术4、DHCP 一、引言 TCP/IP的心脏是网络层。这一层主要由 IP 和 ICMP 两个协议组成。网络层的主要作用是“实现终端节点之…

【C++打怪之路Lv4】-- 类和对象(中)

&#x1f308; 个人主页&#xff1a;白子寰 &#x1f525; 分类专栏&#xff1a;C打怪之路&#xff0c;python从入门到精通&#xff0c;数据结构&#xff0c;C语言&#xff0c;C语言题集&#x1f448; 希望得到您的订阅和支持~ &#x1f4a1; 坚持创作博文(平均质量分82)&#…

ECharts设置xAxis轴的name位置

x轴的name默认是显示在x轴的最后面&#xff0c;但是需求要把name 显示在x轴的上方&#xff0c;所以需要设置nameTextStyle&#xff0c;设置行高&#xff0c;padding和verticalAlign xAxis: { type: value, name: 个, nameTextStyle: { lineHeight: 30, //标题…

第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)

梁哲&#xff0c;同济大学长聘特聘教授&#xff0c;国家杰青、首届国家杰青延续项目获得者、上海市曙光学者、上海市优秀学术带头人。本科毕业于新加坡国立大计算机工程系、硕士毕业于新加坡国立大学工业与系统工程系、博士毕业于美国新泽西州立大学工业工程系。理论研究主要集…

Steam黑神话悟空禁止更新进入游戏的解决方案

首先打开该网站&#xff1a;https://steamdb.info/app/2358720/ 2358720即为游戏ID 网页下翻&#xff0c;找到更新历史&#xff1a;https://steamdb.info/app/2358720/history/ 然后在Steam的steamapps下&#xff0c;找到后缀为2358720的文件&#xff0c;右击记事本打开 将St…

【Java】虚拟线程与Java 8普通线程池的对比

文章目录 IO密集型任务高并发Web服务器异步编程微服务架构大规模并行处理事件驱动的应用不适用的场景使用对比Java 8普通线程池虚拟线程 性能分析资源消耗并发能力性能测试 总结 在JDK 21之前&#xff0c;Java并发编程主要依赖于传统的线程池&#xff0c;如Java 8中的 Executo…

【C语言】指针详解(一)

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1.内存与地址2.指针变量与地址2.1 取地址操作符&2.2 指针变量2.3 指针类型2.4 解引用操作符2.5 指针变量的大小 3. 指针变量类型的意义3.1 指针的解引用 4. const修饰指针4.1 const修饰变量4.2 const修饰指针变量…