【优选算法必刷100题】第017-018题(二分查找——附二分查找算法简介),在排序数组中查找元素的第一个和最后一个位置

【优选算法必刷100题】第017-018题(二分查找——附二分查找算法简介),在排序数组中查找元素的第一个和最后一个位置

🔥个人主页:Cx330🌸

❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》

《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔

🌟心向往之行必能至


🎥Cx330🌸的简介:


目录

前言:

二分查找算法简介:

17. 二分查找

解法:

算法流程:

C++算法代码:

二分查找算法模板:

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

解法:

总结:


前言:
聚焦算法题实战,系统讲解三大核心板块:“精准定位最优解”——优选算法,“简化逻辑表达,系统性探索与剪枝优化”——递归与回溯,“以局部最优换全局高效”——贪心算法,讲解思路与代码实现,帮助大家快速提升代码能力

二分查找专题


二分查找算法简介:

二分查找(Binary Search),也称为折半查找,是一种高效的有序数组查找算法。其核心思想是通过不断将搜索区间减半,快速缩小目标值的可能范围,最终找到目标值或确定其不存在。该算法的时间复杂度为 O(log n),远优于顺序查找的 O (n),在处理大规模有序数据时优势显著


17. 二分查找

题目链接:

704. 二分查找 - 力扣(LeetCode)

题目描述:

题目示例:

解法:

算法流程:

定义 left,right指针,分别指向数组的左右区间。

找到待查找区间的中间点 mid ,找到之后分三种情况讨论:

  • arr[mid]==target 说明正好找到,返回 mid 的值;
  • arr[mid]>target 说明 [mid,right] 这段区间都是大于 target 的。因此舍去右边区间,往左边[left,mid-1] 的区间继续查找,既让 right=mid-1,然后重复 2 过程
  • arr[mid]<target 说明[left,mid]这段区间的值都是小于 target 的。因此舍去左边区间,在右边][mid+1,right] 区间继续查找,即让 left=mid-1,然后重复 2 过程

当 left 与 right 错开时,说明整个区间都没有这个数,返回 -1;

C++算法代码:

class Solution { public: int search(vector<int>& nums, int target) { int left=0,right=nums.size()-1; while(left<=right) { int mid=left+(right-left)/2;//防止数据溢出 if(nums[mid]<target) left=mid+1; else if(nums[mid]>target) right=mid-1; else return mid; } return -1; } };

二分查找算法模板:

 int left=0,right=nums.size()-1; while(left<=right) { int mid=left+(right-left)/2;//防止数据溢出 if(……………………) left=mid+1; else if(…………………………) right=mid-1; else return …………………………; }

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

题目链接:

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

题目描述:

题目示例:

解法:

算法思路:

用的还是二分思想,就是根据数据的性质,在某种判断条件下将区间一分为二,然后舍去其中一个区间,然后再另一个区间内查找;

方便叙述,用 x 表示该元素,resleft 表示左边界,resright 表示右边界

寻找左边界思路:

寻找左边界:我们需要注意到以左边界划分的两个区间的特点

  • 左边区间 [left, resLeft - 1] 都是小于 x 的;
  • 右边区间(包括左边界) [resLeft, right] 都是大于等于 x 的;

因此,关于 mid 的落点,我们可以分为下面两种情况:

  • 当我们的 mid 落在 [left, resLeft - 1] 区间的时候,也就是 arr[mid] < target 。说明 [left, mid] 都是可以舍去的,此时更新 left 到 mid + 1 的位置, 继续在 [mid + 1, right] 上寻找左边界;
  • 当 mid 落在 [resLeft, right] 的区间的时候,也就是 arr[mid] >= target 。 说明 [mid + 1, right] (因为 mid 可能是最终结果,不能舍去)是可以舍去的,此时更新 right 到 mid 的位置,继续在 [left, mid] 上寻找左边界;

由此,就可以通过⼆分,来快速寻找左边界;

注意:这里找中间元素需要向下取整。

因为后续移动左右指针的时候:

  • 左指针: left = mid + 1 ,是会向后移动的,因此区间是会缩小的;
  • 右指针: right = mid ,可能会原地踏步(比如:如果向上取整的话,如果剩下 1,2 两个元素, left == 1 , right == 2 , mid == 2 。更新区间之后, left,right,mid 的值没有改变,就会陷入死循环)

因此⼀定要注意,当 right = mid 的时候,要向下取整。

寻找右边界思路:

寻右右边界: 用resRight 表示 右边界, 我们注意到右边界的特点:

  • 左边区间 (包括右边界) [left, resRight] 都是小于等于 x 的;
  • 右边区间 [resRight+ 1, right] 都是大于 x 的;

因此,关于 mid 的落点,我们可以分为下面两种情况:

  • 当我们的 mid 落在 [left, resRight] 区间的时候,说明 [left, mid - 1] ( mid 不可以舍去,因为有可能是最终结果) 都是可以舍去的,此时更新 left 到 mid的位置
  • 当 mid 落在 [resRight+ 1, right] 的区间的时候,说明 [mid, right] 内的元素是可以舍去的,此时更新 right 到 mid - 1 的位置

由此,就可以通过⼆分,来快速寻找右边界;

注意:这里找中间元素需要向上取整。

因为后续移动左右指针的时候:

  • 左指针: left = mid ,可能会原地踏步(比如:如果向下取整的话,如果剩下 1,2 两个元素, left == 1, right == 2,mid == 1 。更新区间之后, left,right,mid 的值没有改变,就会陷入死循环)
  • 右指针: right = mid - 1 ,是会向前移动的,因此区间是会缩小的;

因此⼀定要注意,当 right = mid 的时候,要向下取整。

C++算法代码:

class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int begin=0,end=0,mid=0; if (nums.empty()) { return {-1, -1}; } //1.查找区间左端点 int left=0,right=nums.size()-1; while(left<right) { mid=left+(right-left)/2; if(nums[mid]<target) left=mid+1; else right=mid; } if(nums[left]==target) begin=left; else return{-1,-1}; //2.查找区间右端点 left=0,right=nums.size()-1; while(left<right) { mid=left+(right-left+1)/2; if(nums[mid]<=target) left=mid; else right=mid-1; } if(nums[right]==target) end=right; else return{-1,-1}; return{begin,end}; } };

总结:

往期回顾:

【优选算法必刷100题】第015-016题(滑动窗口):串联所有单词的子串,最小覆盖子串

Read more

Flutter 三方库 fp_growth 的鸿蒙化适配指南 - 实现具备频繁项集挖掘与关联规则分析的数据挖掘引擎、支持端侧购物篮分析与用户行为预测实战

Flutter 三方库 fp_growth 的鸿蒙化适配指南 - 实现具备频繁项集挖掘与关联规则分析的数据挖掘引擎、支持端侧购物篮分析与用户行为预测实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 fp_growth 的鸿蒙化适配指南 - 实现具备频繁项集挖掘与关联规则分析的数据挖掘引擎、支持端侧购物篮分析与用户行为预测实战 前言 在进行 Flutter for OpenHarmony 开发时,如何从海量的用户操作日志中发现潜在的规律?例如:哪些功能常被组合使用?如果用户点击了 A,有多大几率会点击 B?fp_growth 是数据挖掘领域经典的“频繁项集(Frequent Itemset)”挖掘算法。本文将探讨如何在鸿蒙端构建极致、智能的本地化数据分析底座。 一、原直观解析 / 概念介绍 1.1 基础原理 FP-Growth(Frequent Pattern Growth)算法相比传统的 Apriori 算法,最大的优势在于它不需要多次扫描原始数据库。它通过构建一棵紧凑的“

By Ne0inhk
Flutter for OpenHarmony:Flutter 三方库 gql_link — 掌握鸿蒙端 GraphQL 请求拦截与扩展核心(适配鸿蒙 HarmonyOS Next ohos)

Flutter for OpenHarmony:Flutter 三方库 gql_link — 掌握鸿蒙端 GraphQL 请求拦截与扩展核心(适配鸿蒙 HarmonyOS Next ohos)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net。 Flutter for OpenHarmony:Flutter 三方库 gql_link — 掌握鸿蒙端 GraphQL 请求拦截与扩展核心(适配鸿蒙 HarmonyOS Next ohos) 在现代 App 开发中,GraphQL 的灵活性让我们能精准获取数据。然而,一个健壮的 GraphQL 架构不仅需要发送请求,更需要对请求进行“手术刀”级的拦截、转换和链路编排。例如:统一注入身份 Token、自动日志记录、根据网络状况切换端点等。 在 Flutter for OpenHarmony 开发中,gql_link 库就是这套架构的灵魂所在。它定义了抽象的 Link 通信契约,让我们能像插拔积木一样组合不同的通信能力。今天,

By Ne0inhk
Flutter for OpenHarmony: Flutter 三方库 simple_logger 为鸿蒙系统开发打造最纯粹的日志调试体验(极简主义者的首选)

Flutter for OpenHarmony: Flutter 三方库 simple_logger 为鸿蒙系统开发打造最纯粹的日志调试体验(极简主义者的首选)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在进行 OpenHarmony 应用调试时,虽然控制台有原始的 print,但在处理复杂的异步流、网络状态变更或多层级渲染时,简单的打印往往会导致信息洪流,难以寻找重点。如果你不需要像 talker 或 logger 那么繁重的全家桶方案,只想在控制台中看到一点色彩和清晰的层级,那么这个库就是为你准备的。 simple_logger 完美诠释了“大道至简”。它不依赖任何原生 C++ 接口,纯 Dart 实现,能在鸿蒙设备上以极低的资源占用提供带有级别过滤(Level Filtering)和漂亮格式的日志输出。 一、日志过滤层级模型 simple_logger 允许你根据开发阶段动态调整输出强度。 只打印 INFO 及以上 日志级别 (Level) FINE (调试详情) INFO (常规业务)

By Ne0inhk
Ubuntu 22.04 安装 NVIDIA 显卡驱动完整步骤

Ubuntu 22.04 安装 NVIDIA 显卡驱动完整步骤

Ubuntu 22.04 安装 NVIDIA 显卡驱动完整步骤 一、准备工作 卸载旧版 NVIDIA 驱动(如有) sudoapt purge nvidia-* sudoapt autoremove 禁用开源驱动 Nouveau Nouveau 是 Ubuntu 自带的显卡驱动,与 NVIDIA 驱动冲突,需禁用: sudonano /etc/modprobe.d/blacklist.conf 在文件末尾添加以下内容: blacklist nouveau options nouveau modeset=0 保存后执行: sudo update-initramfs -usudoreboot 重启后验证是否禁用成功(无输出即成功): lsmod |grep nouveau 更新系统

By Ne0inhk