文章目录
目录
文章目录
一、二分查找
1. 整数二分
1.1 二分查找算法模板1
1.2 二分查找算法模板2
1.3 二分查找算法模板3
1.4 二分查找算法模板4
1.5 二分查找算法模板5
练习题目+详解
2. 浮点数二分
总结
一、二分查找
1. 整数二分
二分查找:也称折半搜索,对数搜索,是用来在一个有序数组中查找某一元素的算法。
例子:在一个升序数组中查找一个数。每次考察数组当前部分的中间元素(middle),如果中间元素刚好是目标元素(target),就结束搜索。如果中间元素小于所查找的值,就在数组左半部分[left,middle]查找;如果中间元素大于所查找的值,就在数组右半部分[middle,right]查找。
二分搜索法可以用来查找满足某一条件的最大(最小)值。
要求满足某种条件的最大值最小可能情况(最大值最小化),首先的想法是从小到大枚举这个作为答案的[最大值],然后去判断是否合法。若答案单调,就可以使用二分搜索法来更快的找到答案
使用二分搜索法解决[最大值最小化]条件:
-
答案在一个固定区间内
-
比较容易判断某个值是否符合条件
-
可行解对于区间满足一定的单调性(x符合条件,那么x-1或x+1也符合条件)
- 时间复杂度:最优情况O(1),平均/最坏时间复杂度O(log n)
1.1 二分查找算法模板1
算法思路
假设目标值在闭区间[l,r]中,每次将区间长度缩小一半,当l=mid时,找到目标值
区间[l,r]划分为[l,mid-1]和[mid+1,r];更新操作为r=mid-1或l=mid+1。
int binarySearch(int[] nums, int target){
if(nums == null || nums.length == 0){ //数组为空
return -1;
}
int l = 0, r = nums.length - 1; //设置左右边界
while(l <= r){
int mid = l + (r-l) / 2; // 等同于mid=(l+r)/2,这种写法是为了防止数组越界,也可以写为(l+r) >>> 1
if(nums[mid] == target){ //最终target=mid,输出mid
return mid;
}else if(nums[mid] < target) { //目标值在(mid,r]之间
l = mid + 1;
}else { //目标值在[l,mid)之间
r = mid - 1;
}
}
// 最后判断: l>r 即数组不存在
return -1;
}
1.2 二分查找算法模板2
算法思路
假设目标值在闭区间[l,r]中,每次将区间长度缩小一半,当l=left时,找到目标值
区间[l,r]划分为[l,mid]和[mid+1,r];更新操作为r=mid或l=mid+1(与模板一的区别是界限不同)
int binarySearch(int[] nums, int target){
if(nums == null || nums.length == 0){ //数组为空
return -1;
}
int l = 0, r = nums.length - 1; //设置左右边界
while(l <= r){
int mid = l + (r-l) / 2;
if(nums[mid] > target) { //目标值在[l,mid]之间
r = mid;
}else if(nums[mid] < target){
l = mid+1;
}else{
r = mid;
}
}
if(nums[l] == target){
return l; //当l=left时,找到目标值的下标
}
return -1;
}
1.3 二分查找算法模板3
算法思路
假设目标值在闭区间[l,r]中,每次将区间长度缩小一半,当l=right时,找到目标值
区间[l,r]划分为[l,mid-1]和[mid,r];更新操作为r=mid-1或l=mid(与模板一的区别是界限不同)
int binarySearch(int[] nums, int target){
if(nums == null || nums.length == 0){ //数组为空
return -1;
}
int l = 0, r = nums.length - 1; //设置左右边界
while(l <= r){
int mid = (l+r+1) / 2; //这种版本会有边界问题,计算mid要加1
if(nums[mid] > target) { //目标值在[l,mid]之间
r = mid-1;
}else if(nums[mid] < target){
l = mid;
}else{
r=mid-1;
}
}
if(nums[r] == target){
return r; //当l=right时,找到目标值的下标
}
return -1;
}
1.4 二分查找算法模板4
关于开闭区间问题
二分查找 [left, right)
-
用于查找需要访问数组中当前索引及其直接右邻居索引的元素或条件。
-
使用元素的右邻居来确定是否满足条件,并决定是向左还是向右。
-
保证查找空间在每一步中至少有 2 个元素。
-
需要进行后处理。 当你剩下 1 个元素时,循环 / 递归结束。 需要评估剩余元素是否符合条件。
// 二分查找 [left, right)
int binarySearch2(int[] nums, int target){
if(nums == null || nums.length == 0)
return -1;
// 定义target在左闭右开的区间里,即:[left, right)
int left = 0, right = nums.length;
// 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
while(left < right){
int mid = left + (right - left) / 2;
if(nums[mid] == target){
return mid;
}
else if(nums[mid] < target) {
// target 在右区间,在[mid + 1, right)中
left = mid + 1;
}
else {
// target 在左区间,在[left, middle)中
right = mid;
}
}
//当 left == right
if(left != nums.length && nums[left] == target) return left;
return -1;
}
1.5 二分查找算法模板5
二分查找 (left, right)
搜索需要访问当前索引及其在数组中的直接左右邻居索引的元素或条件。
-
搜索条件需要访问元素的直接左右邻居。
-
使用元素的邻居来确定它是向右还是向左。
-
保证查找空间在每个步骤中至少有 3 个元素。
-
需要进行后处理。 当剩下 2 个元素时,循环 / 递归结束。 需要评估其余元素是否符合条件。
// 二分查找 (left, right)
int binarySearch3(int[] nums, int target) {
if (nums == null || nums.length == 0)
return -1;
int left = 0, 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) {
// target 在右区间,在(middle, right)中
left = mid;
} else {
// target 在左区间,在(left, middle)中
right = mid;
}
}
// 当: left + 1 == right
if(nums[left] == target) return left;
if(nums[right] == target) return right;
return -1;
}
关于模板中出现的边界问题
更新之后的mid仍然为L,左右边界没有发生变化,会使while陷入死循环,所以求mid=(r+l+1)/2

练习题目+详解
练习题1

思路
思路也很简单,就是用二分法找到每一个数字的下标,这里要注意,我们需要找到每个元素第一次出现的位置,所以需要设置l<r,然后递归的时候r=mid, 这样如果目标值存在的话,就返回l的位置。
代码
public class 二分查找 {
static int a[] = new int[10^6+10]; //定义一个数组a的全局变量
static int binarySearch(int x, int n) { //x是目标值,n是数组长度
int l = 0; int r = n-1 ;
while (l<r){
int mid = (l+r)/2;
if(a[mid] < x) l = mid+1;
else r = mid;
}
//找到目标值,返回下标
if(a[l] == x) return l+1; //注意:从1开始编号
else return -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//用户输入n,m 分别代表数组长度,询问次数
int n = sc.nextInt(), m = sc.nextInt();
//这里读入数组
for(int i = 0; i < n; i++){
a[i] = sc.nextInt();
}
//挨个找数字的下标
for(int i = 0; i < m; i++){
int q = sc.nextInt();
int ans = binarySearch(q, n);
System.out.print(ans + " ");
}
}
}
练习题2
给你一个按照非递减顺序排列的整数数组
nums,和一个目标值target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回[-1, -1]。你必须设计并实现时间复杂度为O(log n)的算法解决此问题。
思路
直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 target 的下标,但这个方法的时间复杂度为 O(n),没有利用到数组升序排列的条件。由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。
考虑 target 开始和结束位置,其实我们要找的就是数组中「第一个等于 target 的位置」(记为 left)和「第一个大于 target 的位置减一」(记为 right)。
二分查找中,寻找 left 即为在数组中寻找第一个等于 target 的下标,寻找 right 即为在数组中寻找第一个大于 target 的下标,然后将下标减一。两者的判断条件不同,为了代码的复用,我们定义 searchRange(nums,target) 表示在 nums数组中二分查找 target 的位置 。
最后,因为 target可能不存在数组中,因此我们需要重新校验我们得到的两个下标 left 和 right,看是否符合条件,不符合就返回 -1,-1。
public class 查找下标 {
public int[] searchRange(int[] nums, int target){
int len = nums.length;
if(len == 0){
return new int[]{-1,-1};
}
int firstPosition = findFirstPosition(nums,target);
if(firstPosition == -1){
return new int[]{-1,-1};
}
int lastPositon = findLastPosition(nums,target);
return new int[]{firstPosition,lastPositon};
}
private int findFirstPosition(int[] nums, int target){
int left = 0;
int right = nums.length-1;
while(left < right){ //这里没有包含left=right的情况
int mid = (left+right)/2;
if(nums[mid] < target){
//在[mid+1,right]之间找
left = mid+1;
}else if(nums[mid] > target){
//在[ledt,mid-1]之间找
right = mid-1;
}else{
//在[left,mid]之间找
right = mid;
}
}
if(nums[left] == target){
return left;
}
return -1;
}
private int findLastPosition(int[] nums, int target){
int left = 0;
int right = nums.length-1;
while(left < right){ //这里没有包含left=right的情况
int mid = (left+right+1)/2;
if(nums[mid] < target){
//在[mid+1,right]之间找
left = mid+1;
}else if(nums[mid] > target){
//在[ledt,mid-1]之间找
right = mid-1;
}else{
//在[mid,right]之间找
left = mid;
}
}
return left;
}
}
- >>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;
- >>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
- 时间复杂度:O_(log n)_
练习题3
整数数组
nums按升序排列,数组中的值 互不相同 。在传递给函数之前,
nums在预先未知的某个下标k(0 <= k < nums.length)上进行了 旋转,使数组变为[nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如,[0,1,2,4,5,6,7]在下标3处经旋转后可能变为[4,5,6,7,0,1,2]。给你 旋转后 的数组nums和一个整数target,如果nums中存在这个目标值target,则返回它的下标,否则返回-1。你必须设计一个时间复杂度为
O(log n)的算法解决此问题。
思路
这道题中,数组本身不是有序的,进行旋转后只保证了数组的局部是有序的,这还能进行二分查找吗?答案是可以的。可以发现的是,我们将数组从中间分开成左右两部分的时候,一定有一部分的数组是有序的。拿示例来看,我们从 6 这个位置分开以后数组变成了 [4, 5, 6] 和 [7, 0, 1, 2] 两个部分,其中左边 [4, 5, 6] 这个部分的数组是有序的,其他也是如此。这启示我们可以在常规二分查找的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分查找的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:
-
如果
[l, mid - 1]是有序数组,且 target 的大小满足[nums[l],nums[mid],则我们应该将搜索范围缩小至[l, mid - 1],否则在[mid + 1, r]中寻找。 -
如果
[mid, r]是有序数组,且 target 的大小满足[nums[mid+1],nums[r]],则我们应该将搜索范围缩小至[mid + 1, r],否则在[l, mid - 1]中寻找。
需要注意的是,二分的写法有很多种,所以在判断 target 大小与有序部分的关系的时候可能会出现细节上的差别。
public class 螺旋数组 {
public int search(int[] nums, int target) {
int n = nums.length;
if (n == 0) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[0] <= nums[mid]) { //如果左边是有序的
if (nums[0] <= target && target < nums[mid]) {//目标值在左边
r = mid - 1;
} else { //如果目标值在右边
l = mid + 1;
}
} else { //如果左边是无序的,就相当于遍历该区间元素了
if (nums[mid] < target && target <= nums[n - 1]) {//目标值在右边
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
}
复杂度分析
-
时间复杂度: O(logn),其中 n 为nums 数组的大小。整个算法时间复杂度即为二分查找的时间复杂度 O(logn)。
-
空间复杂度: O(1) 。我们只需要常数级别的空间存放变量。
2. 浮点数二分
浮点数二分:将整数二分中的mid的类型替换成double,将区间更新操作改为l=mid或r=mid,当区间长度足够小(能求出答案时),就可以结束二分。注:浮点数二分不存在边界问题。
代码示例
double binarySearch(int[] nums,int target){
// eps 表示精度,取决于题目对精度的要求
double l = 0; double r = nums.length-1;
const double eps = 1e-6; //科学计数法1*10^-6 当区间长度小于eps时退出循环
while (r - l > eps){ //当区间长度大于eps时继续二分
double mid = (l + r) / 2;
if (nums[mid] > target ) r = mid;
else l = mid;
}
return l; //最后while循环退出的时候l和r近似相等
}
总结
这里对文章进行总结:
以上就是整理的二分算法的内容,本文仅仅简单介绍了二分算法,而要在具体的题目中真正掌握运用二分算法,还需要多加练习二分算法的各种题目。
Java开发的就业市场正在经历结构性调整,竞争日益激烈
传统纯业务开发岗位(如仅完成增删改查业务的后端工程师)的需求,特别是入门级岗位,正显著萎缩。随着企业技术需求升级,市场对Java人才的要求已从通用技能转向了更深入的领域经验(如云原生、微服务)或前沿的AI集成能力。这也导致岗位竞争加剧,在一、二线城市,求职者不仅面临技术内卷,还需应对学历与项目经验的高门槛。
大模型为核心的AI领域正展现出前所未有的就业热度与人才红利
2025年,AI相关新发岗位数量同比激增543%,单月增幅最高超过11倍,大模型算法工程师位居热门岗位前列。行业顶尖人才的供需严重失衡,议价能力极强,跳槽薪资涨幅可达30%-50%。值得注意的是,市场并非单纯青睐算法研究员,而是急需能将大模型能力落地于复杂业务系统的工程人才。这使得具备企业级架构思维和复杂系统整合经验的Java工程师,在向“Java+大模型”复合人才转型时拥有独特优势,成为企业竞相争夺的对象,其薪资天花板也远高于传统Java岗位。

说真的,这两年看着身边一个个搞Java、C++、前端、数据、架构的开始卷大模型,挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis,稳稳当当过日子。
结果GPT、DeepSeek火了之后,整条线上的人都开始有点慌了,大家都在想:“我是不是要学大模型,不然这饭碗还能保多久?”
先给出最直接的答案:一定要把现有的技术和大模型结合起来,而不是抛弃你们现有技术!掌握AI能力的Java工程师比纯Java岗要吃香的多。
即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地!大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇!
如何学习AGI大模型?
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享**
一、2025最新大模型学习路线
一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。
我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。

L1级别:AI大模型时代的华丽登场
L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。

L2级别:AI大模型RAG应用开发工程
L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。

L3级别:大模型Agent应用架构进阶实践
L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。

L4级别:大模型微调与私有化部署
L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。

整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。
二、大模型经典PDF书籍
书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。(书籍含电子版PDF)

三、大模型视频教程
对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识。

四、大模型项目实战
学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

五、大模型面试题
面试不仅是技术的较量,更需要充分的准备。
在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

1万+

被折叠的 条评论
为什么被折叠?



