Java二分算法题目练习

Java二分算法题目练习

二分算法

二分查找

在这里插入图片描述
题目解析:在一个有序数组中找一个target ,找到返回其下标,找不到返回-1
算法原理:1.暴力解法:遍历整个数组进行查找时间复杂度O(N)
2.朴素二分算法:我们可以发现其数组是可以根据一个值将其分为两部分并且可以比较然后舍弃一部分,此时这个数组具有“二段性”,因此可以使用二分算法
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
classSolution{publicintsearch(int[] nums,int target){//此时就用left和right两个变量在左右两边//使用mid来表示其中间的下标,因为其有序//这样我们每次比较一次其就会干掉一半的数这个效率是很高的int left =0;int right = nums.length -1;while(left <= right){int mid = left +(right - left)/2;//防溢出if(target > nums[mid]){//在[mid+1 , right] left = mid +1;}elseif(target < nums[mid]){//在[left,mid - 1] right = mid -1;}else{return mid;}}return-1;}}
时间复杂度:O(log N )
空间复杂度:O(1)

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

在这里插入图片描述
题目解析:就是给了我们一个target,让我们在一个非递减的数组中找其开始和结束下标,并返回,如果找不到就返回[-1,-1]
解法一:暴力解法 ,时间复杂度O(N)
解法二:朴素二分查找,由于我们不确定找的数是其开始和结束位置,因此有可能全部遍历,因此时间复杂度是O(N)
解法三:左右二分算法
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
classSolution{publicint[]searchRange(int[] nums,int target){int[] ret =newint[2]; ret[0]= ret[1]=-1;if(nums.length ==0){return ret;}int left =0;int right = nums.length -1;//先左边二分while(left < right){int mid = left +(right - left)/2;if(nums[mid]< target){ left = mid +1;}else{ right = mid;}}//此时left与right相遇就会结束if(nums[left]!= target){return ret;}//反之就找到了左端点 ret[0]= left; left =0;//可以不用重置,因此此时上面left对应就是其开始位置 right = nums.length -1;while(left < right){int mid = left +(right - left +1)/2;if(nums[mid]> target){ right = mid -1;}else{ left = mid;}} ret[1]= right;return ret;}}

x的平方根

在这里插入图片描述
在这里插入图片描述
classSolution{publicintmySqrt(int x){//此时如果x<1,此时只保留整数,就是0if(x <1){return0;}//防止数据超出long left =1;long right = x;while(left < right){long mid = left +(right - left +1)/2;if(mid * mid <= x){ left = mid;}else{ right = mid -1;}}return(int)left;}}

搜索插入位置

在这里插入图片描述
题目解析:在一个无重复元素的升序数组中找出其目标值的位置,但是可能不存在,不存在的话就返回其按顺序插入的位置
二分算法:因为其可以将其数组分为>= target和<target的两部分,并且可以舍弃<target这个部分,因此使用二分算法,并且还是当left 等于 right结束
在这里插入图片描述
classSolution{publicintsearchInsert(int[] nums,int target){//使用二分算法int left =0;int right = nums.length -1;while(left < right){int mid = left +(right - left)/2;if(nums[mid]< target){ left = mid +1;}else{ right = mid;}}//注意此时可能从头到尾都是< targetreturn nums[right]< target ? right +1: right;}}

山脉数组的峰顶索引

在这里插入图片描述
题目解析:在一个一边递增,另一边递减的数组中找出其最大值
因此只需要找出其递增和递减中间的值下标就可以
在这里插入图片描述
class Solution { publicint peakIndexInMountainArray(int[] arr) { //因为其山脉我们呢可以分为两部分//峰值左边是递增的//峰值右边是递减的intleft=0;intright= arr.length -1;while(left<right){ int mid =left+(right-left+1)/2;if(arr[mid -1]< arr[mid]){ left= mid; }else{ right= mid -1; } } returnleft; } } 

寻找峰值

在这里插入图片描述
题目解析:在一个数组中,找其峰值,并且可能有多个,只需返回任意一个就行
二分算法:因为其是必然有峰值的,并且是不存在两个元素相同,因此其会出现两种情况,要么是递增,要么递减,因此按照分类使用二分算法
在这里插入图片描述


在这里插入图片描述
class Solution { publicint findPeakElement(int[] nums) { intleft=0;intright= nums.length -1;while(left<right){ int mid =left+(right-left)/2;if(nums[mid]> nums[mid+1]){ right= mid; }else{ left= mid +1; } } returnleft; } } 

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

在这里插入图片描述
题目解析:原本一个自增的数组,经过旋转,让我们找出其最小的值
算法原理:暴力解法:直接遍历找最小值
二分算法:我们可以以最后一个下标的值为基准值,因此数组可以分为两个部分,一半是>nums[n-1],一半是 <= nums[n - 1],就这样根据二段性就可以使用二分算法\
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
classSolution{publicintfindMin(int[] nums){int right = nums.length -1;int n = right;int left =0;while(left < right){int mid = left +(right - left)/2;if(nums[mid]> nums[n]){ left = mid +1;}else{ right = mid;}}return nums[left];}}

点名

在这里插入图片描述
题目解析:就是一个递增的数组,并且其下标和其对应的值是对应的,中间缺了一个数导致其不对应了,我们要找到这个数
在这里插入图片描述
//哈希classSolution{publicinttakeAttendance(int[] records){//使用hashSet<Integer> set =newHashSet<>();for(intrecord: records){ set.add(record);}//先全部将其放入hash中,让后一个一个判断其是否在其中就行int len = records.length;for(int i =0; i < len;i++){if(!set.contains(i)){return i;}}//缺少最后一个return len;}}
//直接遍历classSolution{publicinttakeAttendance(int[] records){//直接遍历for(int i =0;i < records.length;i++){if(records[i]!= i){return i;}}return records.length;}}
//求和classSolution{publicinttakeAttendance(int[] records){//使用求和方式也可以int len = records.length;int sum = len *(len +1)/2;for(int i =0;i < len ;i++){ sum -= records[i];}return sum;}}
//位运算classSolution{publicinttakeAttendance(int[] records){//使用位运算符^int ret =0;for(int i =0;i <records.length; i++){ ret ^= records[i]^ i;//此时最后一个下标没有异或}return ret^records.length;}}
//二分算法classSolution{publicinttakeAttendance(int[] records){//此时就可以将其数字分为两个部分//一部分是其值和下标一样//另一部分是不一样int left =0;int right = records.length -1;while(left < right){int mid = left +(right - left)/2;if(records[mid]== mid){ left = mid +1;}else{ right = mid;}}return records[left]== left ? left +1: left;}}

Read more

Flutter for OpenHarmony:cli_util 告别手写 print,用专业级日志系统构建你的 Dart 命令行工具 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:cli_util 告别手写 print,用专业级日志系统构建你的 Dart 命令行工具 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 随着 Flutter 和 Dart 生态的爆发,越来越多的开发者开始使用 Dart 编写命令行工具(CLI)。从官方的 flutter 工具链,到社区的 melos、very_good_cli,Dart 因其 AOT 编译出的独立二进制文件(无需安装运行时)和极快的启动速度,已成为编写跨平台 CLI 的首选语言。 但在开发 CLI 时,我们经常面临一些底层痛点: * SDK 哪里找? 如何准确找到当前运行环境的 Dart SDK 路径?(用于调用 dart format 或 dart pub)。 * 日志怎么打? 简单的

By Ne0inhk
鸿蒙金融理财全栈项目——运维监控、性能优化、安全加固

鸿蒙金融理财全栈项目——运维监控、性能优化、安全加固

《鸿蒙APP开发从入门到精通》第20篇:鸿蒙金融理财全栈项目——运维监控、性能优化、安全加固 📊🔧🛡️ 内容承接与核心价值 这是《鸿蒙APP开发从入门到精通》的第20篇——运维监控、性能优化、安全加固篇,100%承接第19篇的生态合作、用户运营、数据变现架构,并基于金融场景的运维监控、性能优化、安全加固要求,设计并实现鸿蒙金融理财全栈项目的运维监控、性能优化、安全加固功能。 学习目标: * 掌握鸿蒙金融理财项目的运维监控设计与实现; * 实现应用监控、服务器监控、数据库监控; * 理解性能优化在金融场景的核心设计与实现; * 实现前端优化、后端优化、数据库优化; * 掌握安全加固在金融场景的设计与实现; * 实现代码加固、数据加密、安全审计; * 优化金融理财项目的用户体验(运维监控、性能优化、安全加固)。 学习重点: * 鸿蒙金融理财项目的运维监控设计原则; * 性能优化在金融场景的应用; * 安全加固在金融场景的设计要点。 一、 运维监控基础 🎯 1.1 运维监控定义 运维监控是指对金融理财项目的应用、

By Ne0inhk
国产化消息中间件双雄:东方通TongLINK/Q与华为RabbitMQ的运维核心技术全解析

国产化消息中间件双雄:东方通TongLINK/Q与华为RabbitMQ的运维核心技术全解析

在信创产业全面推进“2+8+N”替代工程的背景下,消息中间件作为分布式系统的“神经中枢”,承担着跨系统数据传输、应用解耦、流量削峰的核心使命,其稳定性、安全性与适配性直接决定政企数字化系统的运行效能。作为国产消息中间件领域的标杆产品,东方通TongLINK/Q凭借三十余年行业积淀的全场景适配能力,与华为RabbitMQ国产化适配版依托鲲鹏架构的高性能优化,成为政企信创改造的首选组合。 对于运维人员而言,熟练掌握两款产品的队列配置、消息路由管理与死信队列处理技术,是保障信创系统高效运转的关键。本文将深度拆解两大产品的核心运维技术,结合实操场景与行业案例,揭秘国产化消息中间件如何通过精细化配置实现业务价值最大化,为信创运维工作提供实战指南。 一、国产化适配基石:两款产品的核心定位与信创价值 消息中间件作为基础软件“三驾马车”之一,是信创生态建设的核心环节。东方通与华为凭借各自技术优势,构建了适配全场景信创需求的消息中间件解决方案,为政企系统替代升级筑牢根基。 (一)东方通TongLINK/Q:深耕行业的国产化消息中间件标杆 东方通TongLINK/Q作为国内最早自主研发的消息

By Ne0inhk
【Linux篇章】线程同步与互斥1:打破多线程并发困境,开启高效程序运行新境界

【Linux篇章】线程同步与互斥1:打破多线程并发困境,开启高效程序运行新境界

上一篇在模拟多线程抢票时,并发抢票出现负数问题,引出了锁的概念。本篇将深入探讨相关知识,包括原子性、线程互斥与同步的概念,介绍条件变量以实现线程同步,讲解 mutex、cond、sem 系列系统接口函数的使用与简单封装。最后,利用这些同步与互斥知识,实现基于生产者 - 消费者模型的普通和环形 BlockingQueue。欢迎阅读! 博主主页:☛☛☛羑悻的小杀马特.-ZEEKLOG博客 ☚☚☚  ☺ 欢迎拜访:羑悻的小杀马特.-ZEEKLOG博客 本篇主题:秒懂百科之探究Linux线程同步与互斥第一讲 制作日期:2025.06.16 隶属专栏:linux之旅 目录 一 ·线程互斥:  1.1原子性: 1.2互斥锁(互斥量)的使用 :  1.3互斥锁使用注意事项: 1.4互斥锁底层原理剖析: 对于硬件角度: 对于软件角度:  1.5封装互斥锁:

By Ne0inhk