【算法】【优选算法】二分查找算法(上)

目录

  • 一、二分查找简介
    • 1.1 朴素二分模板
    • 1.2 查找区间左端点模版
    • 1.3 查找区间右端点模版
  • 二、leetcode 704.⼆分查找
    • 2.1 二分查找
    • 2.2 暴力枚举
  • 三、Leetcode 34.在排序数组中查找元素的第⼀个和最后⼀个位置
    • 3.1 二分查找
    • 3.2 暴力枚举
  • 四、35.搜索插⼊位置
    • 4.1 二分查找
    • 4.2 暴力枚举
    • 五、69.x的平⽅根
    • 4.1 二分查找
    • 4.2 暴力枚举

一、二分查找简介

运用场景:

  • 当数组是有二段性的时候就可以使用,
  • 二段性就是指:我们可以找到一个相同规律每次都能够选取一个数,将当前数组分成两段。
  • 我们计算中点的时候有两种计算方法,mid = (right + left) / 2 = left + (right - left) / 2 和 mid = (right + left +1) / 2 = left + (right - left +1)。
    • 这两种方式对于奇数长度的数组来说,没区别,但是对于偶数长度来说,中点有两个点(比如长度为四的数组,中点就可以是1下标也可以是2下标),第一个就是拿到前一个中点,第二个就是拿到后一个中点。

1.1 朴素二分模板

模版:

while(left <= right) {int mid = left + (right - left) / 2;if(……) left = mid + 1;else if(……) right = mid - 1;else return ……; 
}

1.2 查找区间左端点模版

模版:

while(left < right) {int mid = left + (right - left) / 2;if(……) left = mid + 1;else right = mid; 
}

1.3 查找区间右端点模版

模版:

while(left < right) {int mid = left + (right - left + 1) / 2;if(……) left = mid; else right = mid - 1;
}

这两个模版详解在目录三的3.1题解中,也就是Leetcode 34.在排序数组中查找元素的第⼀个和最后⼀个位置的题解。

细节理解

  • 循环条件left <= right :这是因为,如果当前[left , right ]区间中只有一个元素的时候,我们还是需要进行比较。
  • mid = left + ( right - left) / 2:这是因为,我们直接使用(left + right) / 2来求中间值,如果数组很大那么left + right的值是可能超过int的范围的,减法就没有这种风险。

二、leetcode 704.⼆分查找

题目链接:leetcode 704.⼆分查找
题目描述:

题目解析:

  • 这道题就是在一个有序数组中找到一个等于目标值的元素的下标,没找到就返回-1。

2.1 二分查找

解题思路:

  • 直接套用上面的朴素模版即可。

解题代码:

//时间复杂度:O(logN)
//空间复杂度:O(1)
class Solution {public int search(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) return mid;else if(nums[mid] < target) left = mid + 1;else right = mid - 1;}return -1;}
}

2.2 暴力枚举

解题思路:

  • 直接遍历数组,让目标值与每一个元素相比较,如果相等,那么就返回当前下标。
  • 数组遍历完,没找到相等元素,返回-1即可。

解题代码:

//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {public int search(int[] nums, int target) {for(int i = 0; i < nums.length; i++) {if(nums[i] == target) return i;}return -1;}
}

三、Leetcode 34.在排序数组中查找元素的第⼀个和最后⼀个位置

题目链接:Leetcode 34.在排序数组中查找元素的第⼀个和最后⼀个位置
题目描述:

题目解析:

  • 给的是一个非递减数组,意思就是这个数组中元素的值是一定大于或等于前面一个元素的。
  • 返回数组中等于target的子数组的头尾下标,如果只有一个,那么该下标即是头也是尾,如果没有返回两个-1。
  • 题目要求使用复杂度为O(logN),但是其实O(N^2)和O(N)也能过。

3.1 二分查找

解题思路:

  • 当我们要找的是一段区间,那么我们可以尝试分别去找左端点和右端点,这样就是一个区间了。
  • 我们将数组拆分,可以以等于target来拆分,
    • 分法一:一段是 >= target的元素,一段是 < target元素,这就是求左端点的分法。
    • 分法二:一段是 <= target的元素,一段是 > target元素,这就是求右端点的分法。
  • 上面两种分法,都是不断按照同一个规律,将数组拆分为两段,这就是二段性的体现。
  • 求左端点:
    • 循环条件:left < right 因为我们是求的左端点,其中并不会写返回语句,当我们left和right相等的时候,我们如果还进循环,就会陷入死循环,并且其实这个时候就是我们要求的左端点了。
    • 中点的求法:mid = left + (right - left) / 2; 因为当我们只有两个节点时,求取到后一个节点作为中点时,就让mid指向right了,后续更新mid还会指向这里,陷入死循环。
    • 当mid元素 >= target的时候,因为我们求的是左端点,当前的左端点肯定在[ left , mid]区间之间,并且有可能就是mid,所以要让right指向mid。
    • 当mid元素 < target 的时候,左端点肯定在( mid , right ] 区间,所有让 left = mid + 1;
  • 求右端点:
    • 循环条件:left < right 因为我们是求的右端点,其中并不会写返回语句,当我们left和right相等的时候,我们如果还进循环,就会陷入死循环,并且其实这个时候就是我们要求的右端点了。
    • 中点的求法:mid = left + (right - left + 1) / 2; 因为当我们只有两个节点时,以第一个节点为中点,求取到后面就让mid指向left了,后续更新mid还会指向这里,又陷入死循环。
    • 当mid元素 <= target的时候,因为我们求的是右端点,当前的右端点肯定在[ mid, right ]区间之间,并且有可能就是mid,所以要让left指向mid。
    • 当mid元素 > target 的时候,右端点肯定在[ left, mid ) 区间,所有让 right = mid - 1;
  • 在左右端点求取之间,我们还要更新一下结果中的端点值,如果没找到端点,那么就代表给返回[-1, -1]了。
  • 边界:当数组中没有元素的时候,我们去求端点的时候是会直接越界的,所以这种情况要单独处理。

解题代码:

//时间复杂度:O(logN)
//空间复杂度:O(1)
class Solution {public int[] searchRange(int[] nums, int target) {int[] ret = new int[]{-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;}if(nums[left] == target) ret[0] = left; else return ret;//查找右端点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] = left;return ret;}
}

3.2 暴力枚举

解题思路:

  • 我们直接一个for循环,遍历数组,当遇到等于目标值的时候,再一层for循环遍历区间尾即可。

解题代码:

//时间复杂度:O(n^2)
//空间复杂度:O(1)
class Solution {public int[] searchRange(int[] nums, int target) {int[] ret = new int[]{-1,-1};for(int i = 0; i < nums.length; i++) {if(nums[i] == target) {ret[0] = i;for(int j = i; j < nums.length ;j++) {if(j+1 >= nums.length || nums[j+1] > target) {ret[1] = j;return ret;}}}}return ret;}
}

优化:

  • 我们可以借助滑动窗口的思想,
  • 当我们遇到等于目标值的元素之后,并且left还是初始值的时候,我们就可以将ret[ 0 ]更新。
  • 每次right遇到等于目标值的元素的时候,就更新ret[ 1 ]。
//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {public int[] searchRange(int[] nums, int target) {int[] ret = new int[]{-1,-1};for(int left = -1,right = 0; right < nums.length; right++) {if(nums[right] == target) {ret[1] = right;if(left == -1) {left = right;ret[0] = right;}}if(nums[right] > target) break;}return ret;}
}

四、35.搜索插⼊位置

题目链接:35.搜索插⼊位置
题目描述:

题目解析:

  • 数组是升序的,当数组中有等于target,返回该元素下标。
  • 如果没有,返回比他小的最近元素的下一个下标。

4.1 二分查找

解题思路:

  • 套用上面求左右端点的模版都可以求。
  • 有一种边界情况没有求,也就是示例3的情况。单独考虑。

解题代码:

//时间复杂度:O(logN)
//空间复杂度:O(1)
class Solution {public int searchInsert(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;}if(nums[right] >= target) return right;return right+1;}
}class Solution {public int searchInsert(int[] nums, int target) {int left = 0;int right = nums.length - 1;while(left < right) {int mid = left + (right - left + 1) / 2;if(nums[mid] > target) right = mid - 1;else left = mid;}if(nums[right] >= target) return right;return right+1;}
}

4.2 暴力枚举

解题思路:

  • 直接遍历数组。
  • 处理边界情况,插入0位置或者插入数组尾。

解题代码:

//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {public int searchInsert(int[] nums, int target) {for(int i = 0; i < nums.length; i++) {if(nums[i] == target) return i;if(nums[i] < target && i < nums.length - 1 && nums[i+1] > target) return i+1;}  if(nums[0] >= target) return 0; return nums.length;}
}

五、69.x的平⽅根

题目链接:69.x的平⽅根
题目描述:

题目解析:

  • 求一个数的算术平方根,向下取整。

4.1 二分查找

解题思路:

  • 我们可以将 1 - x 的数分为两个区间:小于x算术平方根的区间,大于等于算术平方根的区间。
  • 因为我们需要求的是小于等于算术平方根的最大值,所以相当于求右端点。
  • 套用模版,处理一下边界情况即可。
  • 因为这道题的x范围是整个int,所以当我们求平方的时候是可能超出int范围的,所以我们使用long。

解题代码:

//时间复杂度:O(logN)
//空间复杂度:O(1)
class Solution {public int mySqrt(int x) {long left = 1;long right = x;//边界情况if(x <= 1) return x;while(left < right) {long mid = left + (right - left + 1) / 2;if(mid * mid <= x) left = mid;else right = mid - 1;}return (int)left;}
}

4.2 暴力枚举

解题思路:直接使用一个for循环,将0 到x 的数遍历,看是否符合要求即可。

解题代码:

//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {public int mySqrt(int x) {for(long i = 0; i <= x; i++) {if(i * i == x) return (int)i;else if(i * i < x && (i+1) * (i+1) > x) return (int)i;}return 0;}
}

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

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

相关文章

自己构建ARM平台DM8镜像

&#xff1f;&#xff1f;&#xff1f; 为什么不使用官方提供的docker版本&#xff0c;测试有问题&#xff0c;分析函数不能使用&#xff0c;报错。 自己构建ARM平台的dm8镜像&#xff0c;参考 https://gitee.com/xlongfu/dm-docker/tree/master&#xff0c;发现一些问题 首先…

Linux之实战命令73:at应用实例(一百零七)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

万字长文解读【深度学习面试——训练(DeepSpeed、Accelerate)、优化(蒸馏、剪枝、量化)、部署细节】

&#x1f33a;历史文章列表&#x1f33a; 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络&#xff08;前馈神经网络与反馈神经网络&#xff09;、常见算法概要汇总万字长文解读…

C++ | Leetcode C++题解之第554题砖墙

题目&#xff1a; 题解&#xff1a; class Solution { public:int leastBricks(vector<vector<int>>& wall) {unordered_map<int, int> cnt;for (auto& widths : wall) {int n widths.size();int sum 0;for (int i 0; i < n - 1; i) {sum wi…

DDei在线设计器V1.2.42版发布

V1.2.42版 新特性&#xff1a; 1.快捷编辑框可以映射到主控件的多个属性上&#xff0c;从而实现快速编辑。 2.跟随图形的支持范围增加&#xff0c;从仅支持线控件到支持所有控件 2.新增控件双击回调函数EVENT_CONTROL_DBL_CLICK&#xff0c;可以用于覆盖默认的快速编辑逻辑…

大数据的实时处理:工具和最佳实践

在当今的数字世界中&#xff0c;数据以前所未有的速度从无数来源生成&#xff0c;包括社交媒体、物联网设备、电子商务平台等。随着组织认识到这些数据的潜在价值&#xff0c;他们越来越多地转向实时处理&#xff0c;以获得即时、可操作的见解。但是&#xff0c;实时处理大数据…

【51单片机】蜂鸣器演奏音乐——小星星天空之城

学习使用的开发板&#xff1a;STC89C52RC/LE52RC 编程软件&#xff1a;Keil5 烧录软件&#xff1a;stc-isp 开发板实图&#xff1a; 文章目录 蜂鸣器按键发声无源蜂鸣器演奏音乐简单乐理小星星天空之城 蜂鸣器 蜂鸣器在开发板的位置如下&#xff1a; 蜂鸣器是一种将电信号转…

【含开题报告+文档+源码】高校校园二手交易平台的设计与实现

开题报告 随着互联网的快速发展&#xff0c;电子商务成为了现代化社会中不可或缺的一部分。线上交易平台的兴起&#xff0c;为商家和消费者创造了更多的交易机会和便利。然而&#xff0c;传统的电商平台通常由一家中央机构管理和控制&#xff0c;对商家和消费者的自由度有一定…

录制的音频听起来非常缓慢,声音很模糊

一、主题 录制的音频听起来非常缓慢&#xff0c;声音很模糊 二、问题背景 硬件&#xff1a;T113&#xff0c;R528等平台系列产品 软件&#xff1a;Tina5.0 三、问题描述 1、复现步骤 使用arecord进行录音。 arecord -Dhw:audiocodec -f S16_LE -r 16000 -c 2 -d 5 /tmp/t…

计算机的错误计算(一百五十)

摘要 探讨 MATLAB 中 的计算精度问题。当 为含有小数的大数或 &#xff08;&#xff09;附近数时&#xff0c;输出会有错误数字。 例1. 已知 计算 直接贴图吧&#xff1a; 另外&#xff0c;16位的正确值分别为 -0.7882256119904400e0、0.1702266977524110e0、-0.…

【网络安全 | 漏洞挖掘】Google SSO用户的帐户接管

未经许可,不得转载。 文章目录 DOM XSS获取 CSRF Token解除Google账户绑定在这篇博文中,我将详细介绍找到针对Google SSO用户的账号接管(ATO)漏洞的过程。 DOM XSS 我遇到 DOM XSS 漏洞的位置非常微妙,因为我遇到了非常严格的WAF。 获取 CSRF Token 在找到XSS漏洞后,我…

2024中国游戏出海情况

01 哪里出海更花钱&#xff1f; 报告显示&#xff0c;中国手游在全球不同市场的获客成本不同&#xff0c;整体来看北美市场竞争更加激烈&#xff0c;其安卓和iOS获客成本是拉丁美洲的12倍和7倍。 按具体市场划分&#xff0c;获客成本最高的TOP 3为韩国、美国和日本&#xff0c…

AI写作(七)的核心技术探秘:情感分析与观点挖掘

一、AI 写作中的关键技术概述 情感分析与观点挖掘在 AI 写作中起着至关重要的作用。情感分析能够帮助 AI 理解文本中的情感倾向&#xff0c;无论是正面、负面还是中性。在当今信息时代&#xff0c;准确把握用户情绪对于提供个性化体验和做出明智决策至关重要。例如&#xff0c;…

AlphaProof IMO 2024 P1 in LEAN 之 简介

AlphaProof 是用于进行数学证明的人工智能&#xff0c;其中&#xff0c;对于 IMO 2024 中的6道题中的 4 道。本系列博文&#xff0c;就 AlphaProof 对于 IMO 2024 P1 给出的答案进行详细讲述。这里是此系列的第一篇。 IMO 2024 P1 题目如下&#xff1a; IMO 2024 P1 答案 α 为…

CANFD与CAN区别

CANFD帧的帧格式相比于传统CAN帧的帧格式多了以下的不同的&#xff1a; 1.CANFD帧中用RRS位替换了CAN帧中的RTR位&#xff0c;CAN报文中的RTR&#xff08;Remote Transmission Request&#xff09;位是远程帧发送请求位&#xff0c;当RTR位为显性&#xff08;0&#xff09;时&…

并发编程设计模式——Balking模式(三十九)

Balking 模式 多线程下&#xff0c;维护一个共享状态满足某个条件时&#xff0c;执行业务逻辑&#xff1b;当不满足时则立即放弃。通常用互斥锁来确保共享状态线程安全&#xff0c;如果不需要保证共享状态原子性&#xff0c;也可以用 volitle 修饰&#xff0c;替换互斥锁。 Bal…

了解Synchronized与Lock的区别

前言&#xff1a; 在多线程编程中&#xff0c;保证线程安全是至关重要的。Java提供了两种主要的同步机制&#xff1a;synchronized关键字和Lock接口。尽管它们都是为了解决多线程并发访问共享资源的问题&#xff0c;但在使用方式和特性上存在一些显著的差异。 synchronized&am…

DOM操作和事件监听综合练习:利用JS实现图片轮播

我们经常会看到购物网页上有商品图片在自动循环播放&#xff0c;这就是图片轮播&#xff0c;图片轮播‌是一种常见的网页设计元素&#xff0c;用于在网页上自动切换显示多张图片或内容。它通过JavaScript来实现图片的自动轮播效果&#xff0c;结合HTML和CSS来完成布局和样式设置…

Spark 新作《循序渐进 Spark 大数据应用开发》简介

《循序渐进Spark大数据应用开发》由清华大学出版社出版&#xff0c;已于近期上市。该书基于Spark 3.5.1编写&#xff0c;提供24个实战案例26个上机练习&#xff0c;可谓是目前市面上最新的Spark力作。 本文对《循序渐进Spark大数据应用开发》一书做个大致的介绍。 封面部分 …