【算法专题训练】38、二分查找算法

【算法专题训练】38、二分查找算法

1、二分查找

  • 在一个长度为n的数组中要查找一个数字,逐一扫描数组中的每个数字,需要O(n)的时间
  • 如果数组是排序的,那么可以采用二分查找算法进行优化,采用分治思想,将将数组分为三个区域,判断中间值是否命中,如果没命中,继续在其中的一个区域继续进行分治查询

2、LCR 068. 搜索插入位置

题目信息:

  • https://leetcode.cn/problems/N6YdxV/description/
给定一个排序的整数数组 nums 和一个整数目标值 target ,请在数组中找到 target ,并返回其下标。如果目标值不存在于数组中, 返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums =[1,3,5,6], target =5 输出:2 示例 2: 输入: nums =[1,3,5,6], target =2 输出:1 示例 3: 输入: nums =[1,3,5,6], target =7 输出:4 示例 4: 输入: nums =[1,3,5,6], target =0 输出:0 示例 5: 输入: nums =[1], target =0 输出:0 提示: 1<= nums.length <=104-104<= nums[i]<=104 nums 为无重复元素的升序排列数组 -104<= target <=104

解题思路:

  • 1、审题:
  • 输入一个升序排序的整数数组和一个目标值target,要求在数组中查找是否存在目标值,如果存在返回该目标值在数组中的下标位置,
    • 如果不存在,返回插入该数值应该所在的位置
  • 2、解题:题目要求使用二分查找法
  • 使用左右指针left,right分别标记查找范围,取中间值mid
  • 如果mid下标值等于目标值,则返回mid
  • 如果mid值大于目标值,且mid-1小于目标值,则查找到插入位置,如果mid已经是小标0了,也直接返回
  • 如果mid值小于目标值,继续在后半部分查找, left = mid + 1
  • 如果还是没有找到,说明数组中所有元素都大小目标值,应该插入到数组最末尾端

代码实现:

intsearchInsert(vector<int>&nums,int target){int left =0;int right = nums.size()-1;int mid =0;while(left <= right){ mid = left +(right - left)/2;if(nums[mid]== target){return mid;}if(nums[mid]> target){if(mid ==0|| nums[mid -1]< target){return mid;} right = mid -1;}else{ left = mid +1;}}return nums.size();}

3、LCR 069. 山脉数组的峰顶索引

题目信息:

  • https://leetcode.cn/problems/B1IidL/description/
符合下列属性的数组 arr 称为 山峰数组(山脉数组) : arr.length >=3 存在 i(0< i < arr.length -1)使得: arr[0]< arr[1]<... arr[i-1]< arr[i] arr[i]> arr[i+1]>...> arr[arr.length -1] 给定由整数组成的山峰数组 arr ,返回任何满足 arr[0]< arr[1]<... arr[i -1]< arr[i]> arr[i +1]>...> arr[arr.length -1] 的下标 i ,即山峰顶部。 示例 1: 输入:arr =[0,1,0] 输出:1 示例 2: 输入:arr =[1,3,5,4,2] 输出:2 示例 3: 输入:arr =[0,10,5,2] 输出:1 示例 4: 输入:arr =[3,4,5,1] 输出:2 示例 5: 输入:arr =[24,69,100,99,79,78,67,36,26,19] 输出:2 提示: 3<= arr.length <=1040<= arr[i]<=106 题目数据保证 arr 是一个山脉数组 进阶:很容易想到时间复杂度 O(n) 的解决方案,你可以设计一个 O(log(n)) 的解决方案吗? 

解题思路:

  • 1、审题:输入一个山峰数组,就是数据前半部分排序不断升高,后半部分不断降低,要求找出这个山峰的封顶位置
  • 2、解题:
  • 普通解法:遍历整个数组元素,峰顶元素肯定是比前后两个元素都大的数据,需要O(n)算法复杂度
  • 二分查找解法:使用两个指针left,right标记数组的前后两个元素位置,不断计算得出中间元素位置mid
  • 如果mid下标元素,比前后两个元素都大,则命中
  • 如果mid下标元素,比前一个元素大,处于升序部分,则峰顶元素在数组后半部分,反之峰顶元素在前半部分
  • 山峰数组最后有三个元素组成,left与right可以从第二个位置元素开始遍历查找

代码实现:

intpeakIndexInMountainArray(vector<int>&arr){int left =1;int right = arr.size()-2;int mid;while(left <= right){ mid = left +(right - left)/2;if(arr[mid -1]< arr[mid]&& arr[mid]> arr[mid +1]){return mid;}// 升序部分if(arr[mid -1]< arr[mid]){ left = mid +1;}else{ right = mid -1;}}return-1;}

4、LCR 070. 有序数组中的单一元素

题目信息:

  • https://leetcode.cn/problems/skFtm2/description/
给定一个只包含整数的有序数组 nums ,每个元素都会出现两次,唯有一个数只会出现一次,请找出这个唯一的数字。 示例 1: 输入: nums =[1,1,2,3,3,4,4,8,8] 输出:2 示例 2: 输入: nums =[3,3,7,7,10,11,11] 输出:10 提示: 1<= nums.length <=1050<= nums[i]<=105 进阶:采用的方案可以在 O(log n) 时间复杂度和 O(1) 空间复杂度中运行吗? 

解题思路:

  • 二分查找解法
  • 使用异或操作的解法时间复杂度为O(n),没有使用有序数组的特性
  • 将数组元素从最开始位置,两两合在一起判断,查找其中的两个元素是否相等,如果相同则不同的元素在后面
  • 如果不同,需要判断是否是第一组不相同的数组组合,如果不是则继续遍历前面的组合,前面的数组组合刚好两个元素相同则命中。

代码实现:

intsingleNonDuplicate(vector<int>&nums){int res = nums[0];int left =0;int right = nums.size()-1;if(right ==0){return res;}while(left <= right){int mid = left +(right - left)/2; mid =(mid /2)*2;if(mid ==0&& nums[mid]!= nums[mid +1]){return nums[mid];}if(nums[mid]!= nums[mid +1]&& nums[mid -2]== nums[mid -1]){return nums[mid];}if(nums[mid]== nums[mid +1]){ left = mid +2;}else{ right = mid -2;}}return res;}

5、LCR 071. 按权重随机选择

题目信息:

  • https://leetcode.cn/problems/cuyjEf/description/
给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。 例如,对于 w =[1,3],挑选下标 0 的概率为 1/(1+3)=0.25 (即,25%),而选取下标 1 的概率为 3/(1+3)=0.75(即,75%)。 也就是说,选取下标 i 的概率为 w[i]/sum(w) 。 示例 1: 输入: inputs =["Solution","pickIndex"] inputs =[[[1]],[]] 输出: [null,0] 解释: Solution solution =newSolution([1]); solution.pickIndex();// 返回 0,因为数组中只有一个元素,所以唯一的选择是返回下标 0。 示例 2: 输入: inputs =["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"] inputs =[[[1,3]],[],[],[],[],[]] 输出: [null,1,1,1,1,0] 解释: Solution solution =newSolution([1,3]); solution.pickIndex();// 返回 1,返回下标 1,返回该下标概率为 3/4 。 solution.pickIndex();// 返回 1 solution.pickIndex();// 返回 1 solution.pickIndex();// 返回 1 solution.pickIndex();// 返回 0,返回下标 0,返回该下标概率为 1/4 。 由于这是一个随机问题,允许多个答案,因此下列输出都可以被认为是正确的:[null,1,1,1,1,0][null,1,1,1,1,1][null,1,1,1,0,0][null,1,1,1,0,1][null,1,0,1,0,0]...... 诸若此类。 提示: 1<= w.length <=100001<= w[i]<=10^5 pickIndex 将被调用不超过 10000 次 

解题思路:

  • 1、审题: 输入一个整数数组,他有一个pickIndex方法,要求该方法返回数组中的一个下标,返回数组下标的概率和该下标对应元素的值在整个数组中的占比成正比
  • 也就是说,该数组元素值越大,那么返回该元素下标的比例也越高
  • 2、解题:
  • 将上面的问题转换成累加和数组,新数组的元素值表示能够承接的元素范围
  • 使用变量total表示所有数组元素的累加和,根据该total值计算他的随机数,以随机数作为基准值取新的累加数组中获取对应的下标值
  • 要求在新数组中寻找第一个比基准值大的元素,并返回该下标,使用二分法查询方式来解题

代码实现:

classSolution{public:Solution(vector<int>&w){for(auto num : w){ total += num; nums.push_back(total);}}staticintgenRandomNum(int total){// 随机数引擎(生成器) std::random_device rd; std::mt19937 gen(rd());// 定义分布范围 std::uniform_int_distribution<>dis(0, total -1);// 生成随机数int random_num =dis(gen);return random_num;}intpickIndex(){// 生成随机数int p =genRandomNum(total);int left =0;int right = nums.size()-1;while(left <= right){int mid = left +(right - left)/2;if(nums[mid]> p){if(mid ==0|| nums[mid -1]<= p){return mid;} right = mid -1;}else{ left = mid +1;}}return nums.size()-1;}private:int total =0; std::vector<int> nums;};

6、总结

  • 使用二分查找算法的前提是数组要求有序
  • 二分查找的核心思想都是将原有的有序数组分成三个区域,mid中间位置,和前后两个区域,如果没命中mid中间值,根据判断条件缩小查询范围,直接while循环结束

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk