六、二分搜索-算法总结

文章目录

  • 六、二分搜索
    • 6.1 简介
    • 6.2 典型实例 -- 二分查找
    • 6.2 模板
    • 6.3 常见题目
      • 6.3.1 搜索插入位置
      • 6.3.2 搜索二维矩阵
      • 6.3.3 寻找旋转排序中数组中的最小值
      • 6.3.4 寻找旋转排序数组中的最小值 II
      • 6.3.5 搜索旋转排序数组
      • 6.3.6 搜索旋转排序数组 II
  • 总结

六、二分搜索

6.1 简介

给一个有序数组和目标值,找第一次/最后一次/任何一次出现的索引,如果没有出现返回-1
模板四点要素

  • 1、初始化
  • 2、循环退出条件
  • 3、比较中点和目标值
  • 4、判断最后两个元素是否符合:A[mid] ==、<、> target
    时间复杂度O(logn),使用场景一般是有序数组的查找

6.2 典型实例 – 二分查找

704. 二分查找
在这里插入图片描述

class Solution {// 二分搜索最常用模板public int search(int[] nums, int target) {// method1: 基于迭代// int left = 0, right = nums.length-1;// while (left<=right){//     int mid = (left+right)/2;//     if(target > nums[mid]){//         left = mid+1;//     }else if(target < nums[mid]){//         right = mid-1;//     }else{//         return mid;//     }// }// return -1;// method2: 基于递归return search(0, nums.length - 1, nums, target);}private int search(int left, int right, int[] nums, int target) {if (left > right) {return -1;}int mid = (left + right) / 2;if (nums[mid] == target) {return mid;} else if (nums[mid] > target) {return search(left, mid - 1, nums, target);} else {return search(mid + 1, right, nums, target);}}
}

6.2 模板

大部分二分查找类的题目都可以用这个模板,然后做一点特殊逻辑即可
另外二分查找还有一些其他模板如下图,大部分场景模板#3 都能解决问题,而且还能找第一次/最后一次出现的位置,应用更加广泛
在这里插入图片描述

所以用模板#3就对了,详细的对比可以这边文章介绍:二分搜索模板
如果是最简单的二分搜索,不需要找第一个、最后一个位置、或者是没有重复元素,可以使用模板#1,代码更简洁常见题目

6.3 常见题目

6.3.1 搜索插入位置

35. 搜索插入位置
在这里插入图片描述

class Solution {public int searchInsert(int[] nums, int target) {int left = 0;int right = nums.length-1;while(left+1<right){int mid = left + (right - left)/2;if(nums[mid] == target){return mid;}else if(nums[mid] > target){right = mid;}else{left = mid;}}// 对最后两个结果进行判断 (此时:left+1=right)// target逻辑上最终的落点:负无穷,left,right,正无穷if(nums[left] >= target){return left;}else if(nums[right] >= target){return right;}else{return right+1;}}
}

6.3.2 搜索二维矩阵

74. 搜索二维矩阵
在这里插入图片描述

class Solution {public boolean searchMatrix(int[][] matrix, int target) {// 先定位在哪一行int raw = 0;for(int i = 0;i<matrix.length;i++){if(target >= matrix[i][0] && target <= matrix[i][matrix[i].length-1]){if(target == matrix[i][0] || target == matrix[i][matrix[i].length-1]){return true;}raw = i;break;}}// 在定位中搜索目标值int[] raws = matrix[raw];int left = 0, right = raws.length-1;while(left<=right){int mid = left + (right - left) / 2;if(raws[mid] == target){return true;}else if(raws[mid] > target){right = mid -1;}else{left = mid + 1;}}return false;}
}

6.3.3 寻找旋转排序中数组中的最小值

寻找旋转排序数组中的最小值
在这里插入图片描述

在这里插入图片描述

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

6.3.4 寻找旋转排序数组中的最小值 II

154. 寻找旋转排序数组中的最小值 II
在这里插入图片描述

在这里插入图片描述

// method1: 若最小值出现不止一次,此方法定位的最小值位置不能确定是否是原单调递增的最左侧的数据位置
class Solution {public int findMin(int[] nums) {if(nums.length == 1){return nums[0];}int left = 0, right = nums.length - 1;while(left + 1 < right){int mid = left + (right - left) / 2;if(nums[mid] < nums[right]){right = mid;}else if(nums[mid] > nums[right]){left = mid;}else{right--;}}return Math.min(nums[left], nums[right]);}
}
// method2: 若最小值出现不止一次,此方法定位的最小值位置是原单调递增的最左侧的数据位置
class Solution {public int findMin(int[] nums) {if(nums.length == 1){return nums[0];}int left = 0, right = nums.length - 1;while(left + 1 < right){while(left<right && nums[left] == nums[left+1]){ // 去除左侧重复数字(仅保留一个)left++;}while(left<right && nums[right] == nums[right-1]){ // 去除右侧重复数字(仅保留一个)right--;}int mid = left + (right - left) / 2;if(nums[mid] < nums[right]){right = mid;}else if(nums[mid] > nums[right]){left = mid;}}return Math.min(nums[left], nums[right]);}
}

6.3.5 搜索旋转排序数组

33.搜索旋转排序数组
在这里插入图片描述

// method1: 基于两趟搜索
// 时间复杂度 O(logn)
class Solution {public int search(int[] nums, int target) {if(nums.length == 1){return nums[0]==target?0:-1;}// 找到最小值所在位置// 其左侧(若存在)是递增的// 其右侧(包括它自己)是递增的int left = 0, right = nums.length - 1;while(right - left > 1){int mid = left + (right - left) / 2;if(nums[mid] < nums[right]){right = mid;}else{left = mid;}}// 定位最小值的位置int minIndex = nums[left] < nums[right] ? left:right;// target 可能存在于右边if(target>=nums[minIndex] && target<=nums[nums.length-1]){return search(nums, minIndex, nums.length-1,target);}// target 可能存在于左边(注意:nums本身为递增数组)if(minIndex != 0 && (target>=nums[0] && target<=nums[minIndex-1])){return search(nums, 0, minIndex-1,target);}return -1;}private int search(int[] nums,int left, int right, int target){if(right < 0){return -1;}while(left+1<right){int mid = left + (right-left) / 2;if(nums[mid] == target){return mid;}else if(nums[mid] < target){left = mid;}else{right = mid;}}if(nums[left] == target){return left;}else if(nums[right] == target){return right;}return -1;}
}
// method2: 基于一趟搜索
// 时间复杂度 O(logn)
class Solution {public int search(int[] nums, int target) {if(nums.length == 1){return nums[0]==target?0:-1;}int left = 0, right = nums.length - 1;while(right - left > 1){int mid = left + (right - left) / 2;if(nums[mid] == target){return mid;}if(nums[mid] > nums[left]){ // 位于左边较大的单调区间if(target >= nums[left] && target < nums[mid]){right = mid; // 位于闭区间 [left, mid]}else{ // 位于开区间 [-无穷, left] or [mid, 当前区间的右边界] == [mid, right]// 注意[-无穷, left]就是其右侧的较小单调区间left = mid;}}if(nums[mid] < nums[right]){ // 位于右边较小的单调区间if(target > nums[mid] && target <= nums[right]){left = mid; // 位于闭区间 [mid, right]}else{ // 位于开区间 [当前区间的左边界, mid] or [right, +无穷] == [left, mid]// 注意[right, +无穷]就是其左侧的较大单调区间right = mid;}}}// 对最后的两个数据进行判断if(nums[left] == target){return left;}else if(nums[right] == target){return right;}return -1;}}

6.3.6 搜索旋转排序数组 II

搜索旋转排序数组 II
在这里插入图片描述

// mthod1: 基于两趟搜索
// 时间复杂度:O(logn)
class Solution {public boolean search(int[] nums, int target) {// step 1: 定位最小值位置(需要定位原单调递增的最左侧的值的位置)int left = 0, right = nums.length - 1;while(right - left > 1){while(left < right && nums[left] == nums[left+1]){ // 去除左侧重复的数字left++;}while(left < right && nums[right] == nums[right-1]){ // 去除右侧重复的数字right--;}int mid = left + (right - left) / 2;if(nums[mid] < nums[right]){right = mid;}else{left = mid;}}int minIndex = (nums[left] <= nums[right] ? left:right);// step: 判断目标值位于哪个区间中查询if(target>=nums[minIndex] && target <= nums[nums.length - 1]){return search(nums, minIndex, nums.length - 1, target);}if(minIndex !=0 && target >= nums[0] && target <= nums[minIndex-1]){return search(nums, 0, minIndex - 1, target);}return false;}private boolean search(int[] nums, int left, int right, int target){while(right - left > 1){int mid = left + (right - left) / 2;if(nums[mid] == target){return true;}else if(nums[mid] < target){left = mid;}else{right = mid;}}if(nums[left] == target || nums[right] == target){return true;}return false;}
}
// mthod2: 基于一趟搜索
// 时间复杂度:O(logn)
class Solution {public boolean search(int[] nums, int target) {if(nums.length == 1){return nums[0] == target;}int left = 0, right = nums.length - 1;while(right - left > 1){while(left<right && nums[left] == nums[left+1]){left++;}while(left<right && nums[right] == nums[right-1]){right--;}int mid = left + (right - left) / 2;if(nums[mid] == target){return true;}// 当前mid位于左侧区间if(nums[mid] > nums[left]){if(target>=nums[left] && target < nums[mid]){right = mid;}else{left = mid;}}// 当前mid位于右侧区间if(nums[mid] < nums[right]){if(target > nums[mid] && target <= nums[right]){left = mid;}else{right = mid;}}}if(nums[left] == target || nums[right] == target){return true;}return false;}
}

总结

二分搜索四点要素(必背&理解)

  • 1、初始化:start=0、end=len-1
  • 2、循环退出条件:start + 1 < end
  • 3、 比较中间点和目标值:A[mid] ==、<、> target
  • 4、判断最后两个元素是否符合:A[start]、A[end] ? target

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/424288.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电学基础概念详解及三相电公式汇总

​​​​​​​ 本文全面介绍了电路的基本组成、电学核心概念以及三相电的常用公式。首先&#xff0c;通过水力学中的现象类比&#xff0c;生动解释了电路中电池、开关、电阻和灯泡等元素的功能&#xff0c;帮助读者更好地理解电压、电流和电阻之间的关系。随后&#xff0c;详…

【笔记】进制转换

文章目录 一、任意进制转十进制1、整数转化成十进制&#xff08;1&#xff09;二进制转十进制&#xff08;2&#xff09;八进制转十进制 2、小数转化成十进制&#xff08;1&#xff09;二进制转十进制&#xff08;2&#xff09;八进制转十进制 3、代码1、整数转化成十进制2、小…

OpenCV-Python笔记(上)

安装 全局安装 pip install opencv-python项目虚拟环境安装 # 进入项目根路径执行 .venv/bin/pip install opencv-python计算机眼中的图像 一张图片由大小比如&#xff08;100*100&#xff09;决定&#xff0c;说明存在100*100的像素点&#xff0c;每个像素点存在颜色通道&…

Neo4j入门案例:西游记

创建一个基于《西游记》中“孙悟空”的黑神话版本的知识图谱。这个图谱将会包括《西游记》中的一些主要角色、地点、事件以及它们之间的关系。我们将创建至少10个节点和20个关系&#xff0c;并提供相应的Cypher语句。 数据模型定义 实体类型&#xff08;节点&#xff09; 角色…

Nuxt Kit 组件管理:注册与自动导入

title: Nuxt Kit 组件管理:注册与自动导入 date: 2024/9/15 updated: 2024/9/15 author: cmdragon excerpt: Nuxt Kit 为组件的注册和导入提供了灵活高效的解决方案。无论你是要批量导入组件,还是单独处理特定组件,这些工具都能够满足你的需求。使用这些方法可以显著提升…

路径规划——D*算法

路径规划——D*算法 D Star算法是一种用于动态环境下的算法&#xff0c;它可以在环境变化时快速更新路径。 算法原理 D Star算法是一种反向增量式搜索算法&#xff0c;反向即算法从目标点开始向起点逐步搜索&#xff1b;增量式搜索&#xff0c;即算法在搜索过程中会计算每一…

Navicat On-Prem Server 2.0 | MySQL与MariaDB基础管理功能正式上云

近日&#xff0c;Navicat 发布了 Navicat On-Prem Server 2.0 的重大版本更新。这标志着这款自2021年首发的私有云团队协作解决方案迈入了一个崭新的阶段。此次2.0版本的飞跃性升级&#xff0c;核心聚焦于MySQL与MariaDB基础管理功能的全面革新与强化&#xff0c;赋予了用户的操…

leaflet【十】实时增加轨迹点轨迹回放效果实现

实时轨迹回放 在前面有用leaflet-trackplayer实现了一个轨迹回放的效果&#xff0c;单击前往&#xff1a;轨迹回放效果&控制台控制轨迹运动效果 这篇文章主要是实现一下实时增加轨迹点&#xff0c;不改变原来运行轨迹和速度。这里是简易做了一个demo效果&#xff0c;大概…

计算机网络 --- 【1】欢迎来到计算机网络/计算机网络基本概念/计算机网络、互连网、互联网的区别

目录 一、计算机网络学什么&#xff1f; 二、 什么是计算机网络&#xff1f;计算机网络、互联网(因特网&#xff0c;Internet)、互连网(internet)之间的区别&#xff1f; 2.1 计算机网络的定义 2.2 计算机网络与互连网的区别 2.3 互连网 三、总结部分 一、计算机网络学…

Nginx+Tomcat(负载均衡、动静分离)

目录 一、Nginx概述 1.Nginx应用 二、正向代理和反向代理 1.正向代理 1.1主要作用 1.2工作原理 2.反向代理 2.1主要作用 2.2工作原理 三、负载均衡模式 1.轮询 2.最少连接数 3.IP 哈希 4.加权轮询 5.最少时间算法 6.一致性哈希 四、规划部署负载均衡和反向…

oracle数据库安装和配置详细讲解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; Oracle 数据库是全球广泛使用的关系型数据库管理系统 (RDBMS)&#xff0c;提供高性能、可靠性、安全性和可扩展性&#xff0c;广泛应用于企业关键任务系统。下面详细介绍如何在 CentOS 系统上安装和配置 Or…

【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树

在安卓源码的设计中&#xff0c;将将屏幕分为了37层&#xff0c;不同的窗口将在不同的层级中显示。 对这一块的概念以及相关源码做了详细分析&#xff0c;整理出以下几篇。 【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树 【Android 13源码分析】WindowCon…

智能家居环境监测系统设计(论文+源码)

1. 系统方案 系统由9个部分构成&#xff0c;分别是电源模块、烟雾传感器模块、GSM发送短信模块、报警模块、温度传感器模块、人体红外感应模块、按键设置模块、显示模块、MCU模块。各模块的作用如下&#xff1a;电源模块为系统提供电力&#xff1b;烟雾传感器模块检测烟雾浓度&…

[项目实战]EOS多节点部署

文章总览&#xff1a;YuanDaiMa2048博客文章总览 EOS多节点部署 &#xff08;一&#xff09;环境设计&#xff08;二&#xff09;节点配置&#xff08;三&#xff09;区块信息同步&#xff08;四&#xff09;启动节点并验证同步EOS单节点的环境如何配置 &#xff08;一&#xf…

开放系统,面向各类业务需求可提供定制化服务的智慧物流开源了

智慧物流视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。构建基于Ai技术的…

计算机毕业设计 智慧物业服务系统的设计与实现 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Python数据分析 Pandas库-初步认识

Python数据分析 Pandas库-初步认识 认识Pandas ​ pandas是一个非常实用的Python工具&#xff0c;我们可以把它想象成一个超级强大的表格处理工具&#xff0c;它比Excel更智能&#xff0c;操作更为简单。pands可以从各种文件格式&#xff08;CSV、JSON、SQL、Excel&#xff0…

ModbusTCP/RTU转Ethernet/IP(CIP)-Modbus设备与罗克韦尔AB的PLC之间通讯

IGT-DSER智能网关模块支持西门子、三菱、欧姆龙、罗克韦尔AB等各种品牌的PLC之间通讯&#xff0c;同时也支持PLC与Modbus协议的工业机器人、智能仪表、变频器等设备通讯。网关有多个网口、串口&#xff0c;也可选择WIFI无线通讯。无需PLC内编程开发&#xff0c;只要在IGT-DSER智…

AI大模型与产品经理:替代与合作的深度剖析

在创业的征途中&#xff0c;产品经理常常被外界以一种半开玩笑的口吻提及&#xff1a;“就差一个程序员了。”这句话背后&#xff0c;既蕴含着对产品经理创意与策略能力的认可&#xff0c;也揭示了技术实现环节对于产品成功不可或缺的重要性。然而&#xff0c;随着AI技术的飞速…

2024年微电子与纳米技术国际研讨会(ICMN 2024) Microelectronics and Nanotechnology

文章目录 一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题六、咨询 一、会议详情 二、重要信息 大会官网&#xff1a;https://ais.cn/u/vEbMBz提交检索&#xff1a;EI Compendex、IEEE Xplore、Scopus大会时间&#xff1a;2024年9月20-22日地点&#xff1a;成都…