折半查找练习

二分查找针对的是一个有序的数据集合。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为0。

时间复杂度:O(logn)

    数据大小为n的数组,每次只比较中间的值,然后数据规模缩小n/2,最坏的情况也就是一直到查找空间为空的时候,假设k次比对即可找到正确值,(查到空间为空时)n/(2^k)=1,则k=k=log2n,时间复杂度也就是O(logn)。
    时间复杂度为O(logn):假设一个数组的数据大小n为 2^32,大约是四十多亿,用二分查找来查找里面的一个数的话,最多比较32次也就可以得到这个值了,非常恐怖的快。
 

时间复杂度为O(logn)是在使用数组存储数据的情况下,因为折半查找可以通过下标直接访问中间的二分元素,如果使用链表存储数据呢?使用折半查找的时间复杂度是多少?
答案是O(n),而且甚至可能比遍历查找还慢一些(因为遍历的操作比对命令行更少)。
因为每一次找到中间节点然后比对必须从头开始遍历,比对k次的时间也就是T(n/2)+T(n/4)+…T(n/2^k) = T(n-1)【我也不知道我求错没有】,总之基本上就是O(n)的时间复杂度了。
 
折半查找的使用局限:\

  1. 仅能适用于数组结构,并且数组必须是有序数组,否则需要给数组再排序,就算是快排也需要再使用O(nlogn)的时间。需要连续的内存空间来存储数据,理由如上,因为需要使用数组结构存储数据。
  2. 尽量在静态数据中使用,因为动态数据很难保持长时间的有序,那样排序会给算法带来很大的负担。动态查找需要使用其他的查找算法。
  3. 数据量不能太小,较小的数据量中时间复杂度和遍历基本无区别,而太大的数据又无法保证有序和连续的存储空间。

 

// 循环实现
function bsearch (a,k) {let mid,low = 0,high = a.length-1;while(low <= high){mid = Math.floor((low + high)/2);if(a[mid] === k) {return mid}else if(a[mid]<k){low = mid + 1;}else{high = mid - 1;}}return -1;
}// 递归实现
function bsearch (a,k,low,high) {if(!low) {low = 0; high = a.length-1;};if(low > high) return -1;const mid = Math.floor((low + high)/2);if(a[mid] === k) {return mid;}else if(a[mid] < k){return bsearch(a,k,mid+1,high)}else{return bsearch(a,k,low,mid-1)}
}
注意点:
  1. 循环退出条件注意是 low<=high,而不是 low<high。
  2. mid 的取值:实际上,mid=(low+high)/2 这种写法是有问题的。因为如果 low 和 high 比较大的话,两者之和就有可能会溢出。改进的方法是将 mid 的计算方式写成 low+(high-low)/2。更进一步,如果要将性能优化到极致的话,我们可以将这里的除以 2 操作转化成位运算 low+((high-low)>>1)。因为相比除法运算来说,计算机处理位运算要快得多。
  3. low 和 high 的更新low=mid+1,high=mid-1。注意这里的 +1 和 -1,如果直接写成 low=mid 或者 high=mid,就可能会发生死循环。比如,当 high=3,low=3 时,如果 a[3]不等于 value,就会导致一直循环不退出。

二分查找的变形问题

上文所写的二分查找是最基础的一种,数组中没有重复数据并且已排序。

 

 

1、查找第一个值等于给定值的元素

function bsearch (a,k) {let mid,low = 0,high = a.length-1;while(low <= high){mid = Math.floor((low + high)/2);if(a[mid] === k) {// 判断是不是当前数组里第一个等于k的元素if(mid === 0 || a[mid-1] !== a[mid]){return mid;}else{high = mid - 1;}}else if(a[mid]<k){low = mid + 1;}else{high = mid - 1;}}return -1;
}

 

2、查找最后一个值等于给定值的元素

function bsearch (a,k) {let mid,low = 0,high = a.length-1;while(low <= high){mid = Math.floor((low + high)/2);if(a[mid] === k) {// 判断是不是当前数组里第一个等于k的元素if(mid === a.length-1 || a[mid+1] !== k){return mid;}else{high = mid - 1;}}else if(a[mid]<k){low = mid + 1;}else{high = mid - 1;}}return -1;
}

 

3、查找第一个值大于等于给定值的元素

function bsearch (a,k) {let mid,low = 0,high = a.length-1;while(low <= high){mid = Math.floor((low + high)/2);if(a[mid]<k){low = mid + 1;}else{if(mid === 0 || a[mid - 1] < k){return mid;}high = mid - 1;}}return -1;
}

 

4、查找最后一个小于等于给定值的元素

function bsearch (a,k) {let mid,low = 0,high = a.length-1;while(low <= high){mid = Math.floor((low + high)/2);if(a[mid]<=k){if(mid === a.length-1 || a[mid + 1] > k){return mid;}low = mid + 1;}else{high = mid - 1;}}return -1;
}

 

5、查找最后一个大于等于给定值的元素

function bsearch (a,k) {let mid,low = 0,high = a.length-1;while(low <= high){mid = Math.floor((low + high)/2);if(a[mid]<k){low = mid + 1;}else{if(mid === a.length-1 || (a[mid + 1] > k && a[mid - 1] <= k )){return mid;}high = mid - 1;}}return -1;
}

 

扩展题:剑指 Offer II 072. 求平方根

给定一个非负整数 x ,计算并返回 x 的平方根,即实现 int sqrt(int x) 函数。
正数的平方根有两个,只输出其中的正数平方根。
如果平方根不是整数,输出只保留整数的部分,小数部分将被舍去。

var mySqrt = function(x) {let mid=0,low = 0,high = x;if(x === 0 || x === 1) return xwhile(low <= high){mid = low + Math.floor((high-low)/2);if(x/mid === mid){return Math.floor(mid);}else if(x/mid > mid){low = mid + 1;}else{high = mid - 1;}}return Math.floor(low * low < x ? low : low-1); // 向下取整,取low而非mid ,代入数据1即可知
};

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

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

相关文章

苏宁易购移动端首页(rem布局)

技术选型 方案∶采取单独制作移动页面方案技术:布局采取rem适配布局( less rem &#xff0b;媒体查询)设计图:设计图采用750px设计尺寸 设置视口标签以及引入初始化样式 <meta name"viewport" content"widthdevice-width, initial-scale1.0, user-scalable…

快速入门Safetensors

快速入门Safetensors 什么是Safetensors架构常用操作速度对比彩蛋 Safetensors官方网址 什么是Safetensors Safetensors是一种新的简单格式&#xff0c;用于安全存储张量(与pickle相反)&#xff0c;而且速度仍然很快(零拷贝)。 架构 常用操作 # pip install safetensors# L…

AI嵌入式K210项目(26)-二维码识别

文章目录 前言一、什么是二维码&#xff1f;二、实验准备三、实验过程四、API接口总结 前言 本章介绍基于机器视觉实现二维码识别&#xff0c;主要包含两个过程&#xff0c;首先检测图像中是否有二维码&#xff0c;如果有则框出并打印二维码信息&#xff1b; 一、什么是二维码…

揭开Markdown的秘籍:标题|文字样式|列表

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;Markdown指南、网络奇遇记 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. ⛳️Markdown 标题二. ⛳️Markdown 文字样式2.1 &#x1f514;斜体2.2 &…

MacOS 查AirPods 电量技巧:可实现低电量提醒、自动弹窗

要怎么透过macOS 来查询AirPods 电量呢&#xff1f;当AirPods 和Mac 配对后&#xff0c;有的朋友想通过Mac来查询AirPods有多少电量&#xff0c;这个里有几个技巧&#xff0c;下面我们来介绍一下。 透过Mac 查AirPods 电量技巧 技巧1. 利用状态列上音量功能查询 如要使用此功能…

Spring Boot + 七牛OSS: 简化云存储集成

引言 Spring Boot 是一个非常流行的、快速搭建应用的框架&#xff0c;它无需大量的配置即可运行起来&#xff0c;而七牛云OSS提供了稳定高效的云端对象存储服务。利用两者的优势&#xff0c;可以为应用提供强大的文件存储功能。 为什么选择七牛云OSS? 七牛云OSS提供了高速的…

《Git 简易速速上手小册》第6章:Git 在持续集成/持续部署(CI/CD)中的应用(2024 最新版)

文章目录 6.1 CI/CD基础6.1.1 基础知识讲解6.1.2 重点案例&#xff1a;为 Python Web 应用实现 CI/CD6.1.3 拓展案例 1&#xff1a;自动化部署到云平台6.1.4 拓展案例 2&#xff1a;使用 Docker 容器化部署 6.2 Git 与自动化测试6.2.1 基础知识讲解6.2.2 重点案例&#xff1a;为…

【数据结构】数据结构

本文是基于中国MOOC平台上&#xff0c;华中科技大学的《数据结构》课程和浙江大学的《数据结构》课程所作的一篇课程笔记&#xff0c;便于后期讲行系统性查阅和复习。 从个人感受而言&#xff0c;华中科技大学的课程讲解更适合初学者&#xff08;缺点在于&#xff0c;从概念到…

2024-01-06-AI 大模型全栈工程师 - 机器学习基础

摘要 2024-01-06 阴 杭州 晴 本节简介: a. 数学模型&算法名词相关概念; b. 学会数学建模相关知识&#xff1b; c. 学会自我思考&#xff0c;提升认知&#xff0c;不要只会模仿&#xff1b; 课程内容 1. Fine-Tuning 有什么作用&#xff1f; a. 什么是模型训练&#xff…

redis的主从配置模拟(一主双从)

目录 先来给大家扩展机道面试官经常会问到关于redis的题 一、redis有哪些好处 二、redis相比memcached有哪些优势 三、redis常见性能问题和解决方案 四、redis集群的工作原理 五、redis主从的原理 redis的主从配置模拟&#xff08;一主双从&#xff09; 一、准备环境 …

TCP 传输控制协议——详细

目录 1 TCP 1.1 TCP 最主要的特点 1.2 TCP 的连接 TCP 连接&#xff0c;IP 地址&#xff0c;套接字 1.3 可靠传输的工作原理 1.3.1 停止等待协议 &#xff08;1&#xff09;无差错情况 &#xff08;2&#xff09;出现差错 &#xff08;3&#xff09;确认丢失和确认迟到…

JetpackCompose之状态管理

JetPack Compose系列&#xff08;13&#xff09;—状态管理 State 即&#xff0c;状态。官方的解释是&#xff1a; State in an application is any value that can change over time. And ****event can notify a part of a program that something has happened. 可以这样…

113.路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum 22 输出&a…

cleanmymacX和腾讯柠檬哪个好用

很多小伙伴在使用Mac时&#xff0c;会遇到硬盘空间不足的情况。遇到这种情况&#xff0c;我们能做的就是清理掉一些不需要的软件或者一些占用磁盘空间较大的文件来腾出空间。我们可以借助一些专门的清理工具&#xff0c;本文中我们来推荐几款好用的Mac知名的清理软件。并且将Cl…

【Git】Windows下通过Docker安装GitLab

私有仓库 前言基本思路拉取镜像创建挂载目录创建容器容器启动成功登录仓库设置中文更改密码人员审核配置邮箱 前言 由于某云存在人数限制&#xff0c;这个其实很好理解&#xff0c;毕竟使用的是云服务器&#xff0c;人家也是要交钱的。把代码完全放在别人的服务器上面&#xf…

百家cms代审

环境搭建 源码链接如下所示 https://gitee.com/openbaijia/baijiacms 安装至本地后 直接解压到phpstudy的www目录下即可 接下来去创建一个数据库用于存储CMS信息。&#xff08;在Mysql命令行中执行&#xff09; 接下来访问CMS&#xff0c;会默认跳转至安装界面 数据库名称和…

114.乐理基础-五线谱-快速识别五线谱的谱号

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;113.乐理基础-五线谱-五线谱的调号&#xff08;二&#xff09;-CSDN博客 15个调号&#xff0c;如下图&#xff0c;该怎样才能随便拿出一个来就能快速的知道这是什么调号呢&#xff1f; 一共分为三个要点&#xff1…

单片机学习笔记---DS1302时钟

上一节我们讲了DS1302的工作原理&#xff0c;这一节我们开始代码演示。 新创建一个工程写上框架 我们需要LCD1602进行显示&#xff0c;所以我们要将LCD1602调试工具那一节的LCD1602的模块化代码给添加进来 然后我们开始创建一个DS1302.c和DS1302.h 根据原理图&#xff0c;为了…

牛客网SQL进阶114:更新记录

官网链接&#xff1a; 更新记录&#xff08;二&#xff09;_牛客题霸_牛客网现有一张试卷作答记录表exam_record&#xff0c;其中包含多年来的用户作答试卷记录&#xff0c;结构如下表。题目来自【牛客题霸】https://www.nowcoder.com/practice/0c2e81c6b62e4a0f848fa7693291d…

肯尼斯·里科《C和指针》第13章 高级指针话题(2)函数指针

我们不会每天都使用函数指针。但是&#xff0c;它们的确有用武之地&#xff0c;最常见的两个用途是转换表(jump table)和作为参数传递给另一个函数。本节将探索这两方面的一些技巧。但是&#xff0c;首先容我指出一个常见的错误&#xff0c;这是非常重要的。 简单声明一个函数指…