LeetCode 热题100之二分

关于二分,之前也写过一篇,参考二分Acwing

1.搜索插入位置

在这里插入图片描述思路分析:典型的 二分查找算法,用于在一个已排序的数组中查找目标值的位置。如果找到了目标值,返回其索引;如果没有找到,则返回目标值应该插入的位置。

  • 初始化左右边界
  • 二分查找
    • 每次计算mid,通过 mid = left + (right - left) / 2 来避免可能的溢出;
    • 如果目标值 target 与 nums[mid] 相等,则返回 mid
    • 如果 nums[mid] 大于 target,则将右边界 right 移动到 mid - 1,继续在左半边查找;
    • 如果 nums[mid] 小于 target,则将左边界 left 移动到 mid + 1,继续在右半边查找。
  • 返回插入位置:如果没有找到目标值,left 会指向目标值应该插入的位置。此时,left 就是目标值应该插入的索引。

具体实现代码(详解版):

class Solution {
public:int searchInsert(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) {  // 如果找到了目标值return mid;  // 返回该值的索引} else if (nums[mid] > target) {  // 如果目标值小于中间值right = mid - 1;  // 向左半边查找} else {  // 如果目标值大于中间值left = mid + 1;  // 向右半边查找}}return left;  // 返回左边界位置,即目标值应插入的位置}
};
  • 时间复杂度:O(log n),每次查找都会将搜索空间减小一半,最多执行log n次;
  • 空间复杂度:O(1)

2.搜索二维矩阵

在这里插入图片描述
思路分析:由于每一行是升序排列的,而且每列也是升序排列的,我们可以通过二分查找直接在二维矩阵中进行查找,而不需要将矩阵展平为一维数组。

  • 单一的二分查找:我们将二维矩阵视为一个有序的 1D 数组,矩阵的元素总数是 m * n。关键点是将每个中间索引 mid 映射到二维矩阵中的位置,mid / n 对应行,mid % n 对应列。;
  • 索引映射:通过 mid / n 得到对应的行索引,通过 mid % n 得到列索引。这种映射方式相当于将矩阵展平,但不需要额外的空间。

具体实现代码(详解版):

class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {if (matrix.empty() || matrix[0].empty()) return false;int m = matrix.size();int n = matrix[0].size();int left = 0, right = m * n - 1;while (left <= right) {int mid = left + (right - left) / 2;//就这一句不同,yydsint midValue = matrix[mid / n][mid % n]; // 将 1D 索引转换为 2D 索引if (midValue == target) {return true;} else if (midValue < target) {left = mid + 1;} else {right = mid - 1;}}return false;}
};
  • 时间复杂度:O(log(m * n))
  • 空间复杂度:O(1)

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

在这里插入图片描述
思路分析:这个问题可以分为两个子问题:查找目标值的起始位置,查找目标值的结束位置;

  • 1.查找起始位置

    • 设定两个指针,分别指向数组的左右端点;
    • 在每次比较时,我们计算中间位置 mid,然后根据数组的值来调整左右边界;
      • 如果 nums[mid] 大于或等于 target,我们就缩小右边界 r = mid,因为目标值可能在当前的 mid 或左边部分。
      • 如果 nums[mid] 小于 target,说明目标值在右边,因此移动左边界 l = mid + 1。
    • 当 l 和 r 收敛时,我们检查 nums[l] 是否等于 target,如果是,l 就是目标值的 起始位置。
  • 2.查找结束位置

    • 查找 结束位置 的方法与查找起始位置非常相似,但这次我们需要找到 最后一个出现的目标值。因此,在二分查找过程中,当目标值出现时,我们继续往右查找,直到找到最后一个目标值。
    • 使用两个指针 l2 和 r2,开始时设定为整个数组的范围。
    • 计算中间位置 mid,并根据 nums[mid] 和 target 的关系来调整左右边界:
      • 如果 nums[mid] 小于或等于 target,我们可能找到了目标值的最后位置,因此继续向右查找,调整 l2 = mid。
      • 如果 nums[mid] 大于 target,则目标值只能在 mid 左边,因此调整右边界 r2 = mid - 1。
    • 当 l2 和 r2 收敛时,l2 就是目标值的 结束位置。

具体实现代码(详解版)

class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {vector<int> res = {-1, -1};if (nums.empty()) {return res;}// 查找目标值的起始位置int l = 0, r = nums.size() - 1;while (l < r) {int mid = l + (r - l) / 2; // 防止溢出if (nums[mid] >= target) {r = mid; // 目标值可能在左半部分或是 mid 本身} else {l = mid + 1;}}// 确保 nums[l] 是目标值if (nums[l] != target) {return res; // 如果没有找到目标值,直接返回 {-1, -1}}int start = l;// 查找目标值的结束位置int l2 = 0, r2 = nums.size() - 1;while (l2 < r2) {int mid = l2 + (r2 - l2 + 1) / 2; // 防止溢出if (nums[mid] <= target) {l2 = mid; // 目标值可能在右半部分或是 mid 本身} else {r2 = mid - 1;}}int end = l2;// 返回目标值的起始位置和结束位置return {start, end};}
};
  • 时间复杂度:O(log n);
  • 空间复杂度:O(1)

4.搜搜旋转排序数组

在这里插入图片描述
思路分析:旋转后的数组会分为两个升序的部分:一部分可能是从旋转点到数组的末尾,另一部分是从数组的开头到旋转点。我们可以利用二分查找,但需要判断中间元素的位置是处于旋转后的哪个部分。通过这个判断,我们能够缩小搜索范围。

  • 初始化两个指针 left 和 right,分别指向数组的头和尾。;
  • 计算中间位置 mid = left + (right - left) / 2
  • 判断 nums[mid] 是否等于目标值 target,如果是,直接返回 mid。
  • 判断 nums[mid] 是否等于目标值 target,如果是,直接返回 mid。
    • 如果左半部分升序:nums[left] <= nums[mid],此时:
      • 如果 nums[left] <= target < nums[mid],目标值在左半部分,更新 right = mid - 1;
      • 否则,目标值在右半部分,更新 left = mid + 1。
    • 如果右半部分升序:nums[mid] <= nums[right],此时:
      • 如果 nums[mid] < target <= nums[right],目标值在右半部分,更新 left = mid + 1;
      • 否则,目标值在左半部分,更新 right = mid - 1。
  • 如果 left 超过 right,说明目标值不存在于数组中,返回 -1。

具体实现代码(详解版):

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) {return mid;  // 找到目标值,返回索引}// 判断左半部分是否有序if (nums[left] <= nums[mid]) {// 如果目标值在左半部分if (nums[left] <= target && target < nums[mid]) {right = mid - 1;} else {left = mid + 1;}} else {// 右半部分有序// 如果目标值在右半部分if (nums[mid] < target && target <= nums[right]) {left = mid + 1;} else {right = mid - 1;}}}return -1;  // 找不到目标值}
};

5.寻找寻转数组中的最小值

在这里插入图片描述
思路分析:旋转的关键在于数组的最小值。最小值一定在旋转点处,旋转后的数组就像是两个升序数组拼接在一起,最小值一定是较小的部分的第一个元素。通过二分查找来高效地找到最小值的位置:

  • 如果 nums[mid] >= nums[right],说明旋转点在右半部分或是 mid 本身可能是旋转点的前一个位置。此时最小值必然在右半部分,我们将 left = mid + 1。
  • 否则,说明最小值在左半部分或 mid 本身就是最小值,我们将 right = mid。
  • 最终,left == right,nums[left]就是最小值。

具体实现代码(详解版):

class Solution {
public:int findMin(vector<int>& nums) {int left = 0, right = nums.size() - 1;// 二分查找while (left < right) {int mid = left + (right - left) / 2;// 如果 mid 元素大于右边的元素,最小值一定在右边if (nums[mid] > nums[right]) {left = mid + 1;} else {// 如果 mid 元素小于等于右边的元素,最小值可能在左边right = mid;}}// 当 left == right 时,left 就是最小值的位置return nums[left];}
};

6.寻找两个正序数组中的中位数

在这里插入图片描述

真实难题!
思路分析:由于我们需要在两个有序数组中找到中位数,可以考虑通过二分查找的方式,在一个数组中找到合适的分割点,并利用这个分割点将另一个数组分成合适的部分。

  • 中位数的定义:如果合并两个数组后的总元素数是奇数,那么中位数就是中间那个元素;如果合并两个数组后的总元素数是偶数,那么中位数是中间两个元素的平均值。
  • 通过二分查找进行分割
    • 我们将数组 nums1 和 nums2 分成两部分,使得:
      • 左边部分包含的是小于等于右边部分的元素。
      • 两个数组的左部分和右部分的元素个数总是相等(或者左部分多一个)。
    • 我们希望通过二分查找来找到数组 nums1 中的分割点 i,从而通过 i 可以推算出数组 nums2 中的分割点 j。
    • 条件检查:对于每一对 i 和 j,我们检查是否满足:
      • nums1[i-1] <= nums2[j](nums1 左半部分最大值小于等于 nums2 右半部分最小值)
      • nums2[j-1] <= nums1[i](nums2 左半部分最大值小于等于 nums1 右半部分最小值)
      • 如果满足条件,计算并返回中位数。
    • 如果不满足上述条件,调整 i,继续二分查找。

具体实现代码(详解版):

class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {if (nums1.size() > nums2.size()) {// 确保 nums1 是较小的数组return findMedianSortedArrays(nums2, nums1);}int m = nums1.size();int n = nums2.size();int left = 0, right = m;while (left <= right) {int i = left + (right - left) / 2;  // nums1 的分割点int j = (m + n + 1) / 2 - i;       // nums2 的分割点// 处理 nums1[i-1] 和 nums2[j-1] 可能越界的情况int nums1LeftMax = (i == 0) ? INT_MIN : nums1[i - 1];int nums1RightMin = (i == m) ? INT_MAX : nums1[i];int nums2LeftMax = (j == 0) ? INT_MIN : nums2[j - 1];int nums2RightMin = (j == n) ? INT_MAX : nums2[j];// 检查是否找到了合适的分割点if (nums1LeftMax <= nums2RightMin && nums2LeftMax <= nums1RightMin) {// 如果总数为奇数,返回左半部分最大值if ((m + n) % 2 == 1) {return max(nums1LeftMax, nums2LeftMax);}// 如果总数为偶数,返回两者中间的平均值return (max(nums1LeftMax, nums2LeftMax) + min(nums1RightMin, nums2RightMin)) / 2.0;} else if (nums1LeftMax > nums2RightMin) {// nums1[i-1] 太大,缩小 iright = i - 1;} else {// nums2[j-1] 太大,增大 ileft = i + 1;}}return 0.0;}
};
  • 时间复杂度:O(log(min(m,n))
  • 空间复杂度:O(1)

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Python+Appium+Pytest+Allure自动化测试框架-安装篇

文章目录 安装安装ADT安装NodeJs安装python安装appium安装Appium Server&#xff08;可选&#xff09;安装Appium-Inspector&#xff08;可选&#xff09;安装allure安装pytest PythonAppiumPytestAllure框架的安装 Appium是一个开源工具&#xff0c;是跨平台的&#xff0c;用于…

Twitter(X)2024最新注册教程

Twitter 现名为X&#xff0c;因为图标是一只小鸟的形象&#xff0c;大家也叫它小蓝鸟&#xff08;埃隆马斯克于 2023 年对该平台进行了品牌重塑&#xff09;&#xff0c;目前仍然是全球最受欢迎的社交媒体和微博平台之一&#xff0c;全球活跃用户量大概在4.5亿。尤其是欧美国家…

[HCTF 2018]WarmUp 1--详细解析

打开靶机&#xff0c;进入界面&#xff1a; 信息搜集 当前界面没有任何有用信息。 想到查看页面源代码。右键–查看页面源代码 看到hint&#xff1a;<!--source.php--> 进入/source.php页面&#xff0c;看到页面源代码&#xff1a; <?phphighlight_file(__FILE_…

HFSS学习笔记(五)金属过孔、复制模型带激励等问题(持续更新...)

HFSS学习笔记&#xff08;五&#xff09;金属过孔、复制模型带激励等问题&#xff08;持续更新…&#xff09; 一、金属过孔设计 方法一&#xff1a;用介质减去金属圆柱体&#xff0c;然后再添加金属圆柱体 方法二&#xff1a;嵌入金属圆柱 圆柱过孔选择材料为“copper” HFS…

FFmpeg 4.3 音视频-多路H265监控录放C++开发十. 多线程控制帧率。循环播放,QT connect 细节,

在前面&#xff0c;我们总结一下前面的代码。 在 FactoryModeForAVFrameShowSDL 构造函数中 init SDL。 通过 QT timerevent机制&#xff0c;通过startTimer(10);每隔10ms&#xff0c;就会调用timerEvent事件。 在timerEvent事件中&#xff0c;真正的去 读取数据&#xff0c…

「iOS」——知乎日报一二周总结

知乎日报仿写 前言效果Manager封装网络请求线程冲突问题下拉刷新添加网络请求的图片通过时间戳和日期格式化获取时间 总结 前言 前两周内容的仿写&#xff0c;主要完成了首页的仿写&#xff0c;进度稍慢。 效果 Manager封装网络请求 知乎日报的仿写需要频繁的申请网络请求&am…

用流量策略做多出口实验

一、拓扑&#xff1a; 二、配置过程&#xff1a; 1、配置 IP 地址&#xff0c;配置动态路由协议 OSPF 2、AR2 上&#xff0c;配置高级 ACL&#xff0c;允许 ospf 流量、1 到 6、2 到 8、deny 所有 3、写流分类&#xff0c;抓取流量特征 4、写流行为&#xff0c;配置流量动作 5、…

跨境云专线:构建高速、安全的全球业务网络

在企业出海加速的背景下&#xff0c;越来越多的企业需要在全球范围内部署业务&#xff0c;特别是在多个国家和地区之间进行数据传输。然而&#xff0c;跨境网络连接常常面临带宽不足、延迟高、数据安全性差等问题&#xff0c;这给企业的业务运营带来了巨大挑战。为了解决这些问…

leetcode动态规划(二十四)-最长递增子序列

题目 300.最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7…

C++ 内存管理

new与delete 在C语言中&#xff0c;我们已经了解了三个动态内存管理的函数——malloc,calloc以及realloc,通过动态内存开辟&#xff0c;申请和释放空间更加的灵活 int main() {int* arr (int*)malloc(sizeof(int) * 10);for (int i 0; i < 10; i) {arr[i] i;print…

2. JVM的架构模型和生命周期

一、前言 Java 编译器输入的指令流是一种基于栈的指令集架构&#xff0c;还有另一种指令集架构是基于寄存器的指令集架构。 二、两种架构之前的区别 基于栈的架构特点&#xff1a; 设计和实现更简单&#xff0c;适用于资源受限的系统&#xff1b;避开了寄存器的分配难题&am…

Flutter3.22.2中SliverAppBar设置背景色滑动显示颜色错误

在使用Flutter项目开发中&#xff0c;可能会有页面需要滑动收起标题栏的效果&#xff0c;一般都会使用SliverAppBar来实现&#xff0c;当项目的Flutter的SDK版本升级到3.4后&#xff0c;发现使用了SliverAppBar的页面&#xff0c;在滑动过程中&#xff0c;标题栏和状态栏的颜色…

vim 编辑器

1. 学习 vim 的目的 在工作中&#xff0c;要对 服务器 上的文件进行 简单 的修改&#xff0c;可以使用 ssh 远程登录到服务器上&#xff0c;并且使用 vim 进行快速的编辑即可常见需要修改的文件包括&#xff1a;源程序配置文件&#xff0c;例如 ssh 的配置文件 ~/.ssh/config …

瑞派宠物医院轮值总裁胡文强受邀出席第三届宠物产业大会

中国宠物产业蓬勃发展&#xff0c;成为推动国民经济持续增长的重要力量&#xff0c;宠物市场规模持续扩大。为进一步推动宠物产业的创新驱动&#xff0c;加强产业上下游深度交流和协同发展&#xff0c;中国畜牧业协会宠物产业分会于2024年10月15-17日在浙江杭州召开第三届宠物产…

Linux云计算 |【第五阶段】CLOUD-DAY7

主要内容&#xff1a; 在kubernetes平台上理解掌握各种控制器的用法&#xff1a;掌握kubectl管理命令、掌握POD原理、掌握集群调度的规则、熟悉控制器资源文件&#xff1b; 一、kubectl 常用命令 Kubectl是用于控制Kubernetes集群的命令行工具&#xff1b; - 格式&#xff1…

[java][框架]springMVC(1/2)

目标 知道SpringMVC的优点编写SpringMVC入门案例使用PostMan发送请求掌握普通类型参数传递掌握POJO类型参数传递掌握json数据参数传递掌握响应json数据掌握rest风格快速开发 一、SpringMVC简介 1 SpringMVC概述 问题导入 SpringMVC框架有什么优点&#xff1f; 1.1 Spring…

dns主从服务器的配置

主从dns服务器上都要&#xff1a; 关闭防火墙&#xff1a; [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 挂载和下载bind [rootlocalhost ~]# mount /dev/sr0 /mnt [rootlocalhost ~]# dnf install bind -y 主服务器配置&#xff1a; [rootlo…

【大咖云集,院士出席 | ACM独立出版】第四届大数据、人工智能与风险管理国际学术会议 (ICBAR 2024,11月15-17日)--冬季主会场

第四届大数据、人工智能与风险管理国际学术会议 (ICBAR 2024)--冬季主会场 2024 4th International Conference on Big Data, Artificial Intelligence and Risk Management 官方信息 会议官网&#xff1a;www.icbar.net 2024 4th International Conference on Big Data, Art…

linphone sdk sip音视频通话高级教程

本文主要基于c接口讲解linphone结合freeswitch在多平台的运用。大纲如下 linphone sdk下载地址sdk导入本文基于console程序演示,qt工程也行简单的音频呼叫,sip服务器使用freeswitch音频设置(设备、增益、铃声、回声消除、编码等)视频呼叫 默认有vp8 这里导入下h264视频设置(…

【Jenkins】 上传docker包并推送到远程仓库

文章目录 1. 前置工作安装和配置Jenkins设置Docker环境 2. 相关配置流程创建项目配置参数 1. 前置工作 安装和配置Jenkins 在开始使用Jenkins之前&#xff0c;需要确保已经安装和配置了Jenkins服务器。您可以按照以下步骤进行安装和配置&#xff1a; 下载Jenkins并安装&…