Javascript算法——二分查找
1.数组

1.1二分查找
1.搜索索引
开闭matters!!![left,right]与[left,right)
/*** @param {number[]} nums* @param {number} target* @return {number}*/
var search = function(nums, target) {let left=0;let right=nums.length-1;//[left,right],相等时能取到,有意义while(left<=right){let mid =Math.floor((left+right)/2);if(target===nums[mid]){return mid;}else if (target>nums[mid]) {left=mid+1;}else{right=mid-1;}}return -1;};
console.log(search([-1,0,3,5,9,12],2))//-1
console.log(search([-1,0,3,5,9,12],2))//4

VS

/*** @param {number[]} nums* @param {number} target* @return {number}*/
var search = function(nums, target) {// right是数组最后一个数的下标+1,nums[right]不在查找范围内,是左闭右开区间let mid, left = 0, right = nums.length; // 当left=right时,由于nums[right]不在查找范围,所以不必包括此情况while (left < right) {// 位运算 + 防止大数溢出mid = left + ((right - left) >> 1);// 如果中间值大于目标值,中间值不应在下次查找的范围内,但中间值的前一个值应在;// 由于right本来就不在查找范围内,所以将右边界更新为中间值,如果更新右边界为mid-1则将中间值的前一个值也踢出了下次寻找范围if (nums[mid] > target) {right = mid; // 去左区间寻找} else if (nums[mid] < target) {left = mid + 1; // 去右区间寻找} else {return mid;}}return -1;
};
2.搜索插入位置


/*** @param {number[]} nums* @param {number} target* @return {number}*/
var searchInsert = function(nums, target) {let left=0;let right=nums.length-1;//[left,right],相等时能取到,有意义while(left<=right){let mid =Math.floor((left+right)/2);if(target===nums[mid]){return mid;}else if (target>nums[mid]) {left=mid+1;}else{right=mid-1;}}// 分别处理如下四种情况// 目标值在数组所有元素之前 [0, -1]// 目标值等于数组中某一个元素 return middle;// 目标值插入数组中的位置 [left, right],return right + 1// 目标值在数组所有元素之后的情况 [left, right],这是右闭区间,所以 return right + 1return right+1;};
console.log(search([1,3,5,6],0))//0
console.log(search([1,3,5,6],3))//1
console.log(search([1,3,5,6],4))//2
console.log(search([1,3,5,6],7))//4
其余三种都可以归纳为right+1
3.在排序数组中查找元素的第一个和最后一个位置


- 找左边界时,需将right赋给左边界,所以在target<=num[mid]时更新right并更新左边界
- 找右边界时,需将left赋给右边界,所以在target>=num[mid]时更新left并更新右边界
- 情况二,通过rightBorder-leftBorder>1条件判断
var searchRange = function(nums, target) {const getLeftBorder = (nums, target) => {let left = 0, right = nums.length - 1;let leftBorder = -2;// 记录一下leftBorder没有被赋值的情况while(left <= right){let middle = left + ((right - left) >> 1);if(nums[middle] >= target){ // 寻找左边界,nums[middle] == target的时候更新rightright = middle - 1;leftBorder = right;} else {left = middle + 1;}}return leftBorder;}const getRightBorder = (nums, target) => {let left = 0, right = nums.length - 1;let rightBorder = -2; // 记录一下rightBorder没有被赋值的情况while (left <= right) {let middle = left + ((right - left) >> 1);if (nums[middle] > target) {right = middle - 1;} else { // 寻找右边界,nums[middle] == target的时候更新leftleft = middle + 1;rightBorder = left;}}return rightBorder;}let leftBorder = getLeftBorder(nums, target);let rightBorder = getRightBorder(nums, target);// 情况一if(leftBorder === -2 || rightBorder === -2) return [-1,-1];// 情况三if (rightBorder - leftBorder > 1) return [leftBorder + 1, rightBorder - 1];// 情况二return [-1, -1];
};
4.X的平方根
function mySqrt(x) { if (x === 0) return 0; // 特殊情况处理:0的平方根是0 let left = 1; // 搜索范围的左边界 let right = Math.floor(x / 2) + 1; // 搜索范围的右边界,x/2是一个合理的上限,因为平方根不会超过x/2(对于非负整数x) while (left <= right) { let mid = Math.floor((left + right) / 2); // 计算中间值 let square = mid * mid; // 计算中间值的平方 if (square === x) { return mid; // 如果平方正好等于x,直接返回 } else if (square < x) { left = mid + 1; // 如果平方小于x,说明平方根在mid的右侧,移动左边界 } else { right = mid - 1; // 如果平方大于x,说明平方根在mid的左侧或正好是mid(但我们需要整数部分,所以向左移动) } } // 循环结束时,left会指向比实际平方根大的最小整数,而right会指向比实际平方根小的最大整数 // 因为我们需要整数部分,所以返回right(它是最后一个使得mid*mid <= x的mid值) return right;
} // 测试
console.log(mySqrt(4)); // 输出: 2
console.log(mySqrt(8)); // 输出: 2 (8的平方根约为2.8284,取整数部分2)
console.log(mySqrt(15)); // 输出: 3 (15的平方根约为3.8729,取整数部分3)
解释
- 边界条件:
- 如果 x 为0,则直接返回0。
- 搜索范围:
- 左边界
left初始化为1,因为0的平方根是0(已经特殊处理),而任何正数的平方根至少为1。- 右边界
right初始化为 Math.floor(x/2)+1,因为平方根不会超过 x/2(对于非负整数 x)。加1是为了确保在 x 为完全平方数时能够包含这个平方根。- 二分查找:
- 在每次迭代中,计算中间值
mid及其平方square。- 根据
square与 x 的比较结果,移动左边界或右边界。- 返回结果:
- 循环结束时,返回
right,它是最后一个使得mid * mid <= x的mid值,也就是我们要找的平方根的整数部分。这种方法的时间复杂度是 O(logn),其中 n 是 x 的值,因为每次迭代都会将搜索范围减半。
更精确 (待进一步补充)
function mySqrt(x) { if (x === 0) return 0; // 特殊情况处理:0的平方根是0 let guess = x; // 初始猜测值设为x本身(对于非负整数,平方根不会超过x本身) let epsilon = 1; // 精度控制,用于判断迭代是否结束 while (Math.abs(guess * guess - x) >= epsilon) { // 牛顿迭代公式:guess = (guess + x / guess) / 2 guess = Math.floor((guess + Math.floor(x / guess)) / 2); // 为了确保精度,逐步减小epsilon epsilon /= 10; } return guess;
} // 测试
console.log(mySqrt(4)); // 输出: 2
console.log(mySqrt(8)); // 输出: 2 (8的平方根约为2.8284,取整数部分2)
console.log(mySqrt(15)); // 输出: 3 (15的平方根约为3.8729,取整数部分3)
- 初始猜测值:
- 对于非负整数 x,初始猜测值设为 x 本身,因为平方根不会超过 x 本身。
- 牛顿迭代公式:
- 牛顿迭代法的公式为:new_guess=(old_guess+x/old_guess)/2
- 这个公式通过不断迭代来逼近平方根的值。
- 精度控制:
- 使用
epsilon来控制精度,初始设为 1。- 每次迭代后,将
epsilon除以 10,逐步减小精度要求,确保最终结果的准确性。- 取整:
- 使用
Math.floor函数来确保结果只保留整数部分。
5.有效的完全平方数(与上类似)
/*** @param {number} num* @return {boolean}*/
var isPerfectSquare = function(num) {if(num===1)return truelet left=1;let right=Math.floor(num/2)+1;//天天天,你条件写错了!!!!while(left<=right){let mid = Math.floor((left+right)/2);let square=mid*mid;if(square===num){return true;}else if(square>num){right=mid-1;}else{left=mid+1;}}return false;
};
- 题目:给定一个n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果目标值存在返回下标,否则返回-1。
- 解析:这是二分查找算法的最基本应用。通过设定左右指针,不断缩小搜索范围,直到找到目标值或确定目标值不存在。
- 题目:给定一个按照非递减顺序排列的整数数组nums,和一个目标值target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回[-1, -1]。
- 解析:这个问题可以先用二分查找找到目标值的一个位置,然后通过双指针从中间向两边扩散,找到目标值的开始位置和结束位置。这种方法的时间复杂度为O(log n + k),其中n是数组的长度,k是目标值在数组中出现的次数。
- 题目:在旋转排序数组中查找目标值(假设数组中不存在重复元素)。
- 解析:旋转排序数组是指一个递增排序数组经过一次旋转得到的数组。这个问题可以通过修改二分查找算法来解决。首先,找到数组中的“旋转点”(即数组从递增变为递减的点),然后根据目标值与旋转点的大小关系,在数组的左侧或右侧进行二分查找。
- 题目:在有序数组中查找第一个大于给定值的元素。
- 解析:这个问题可以通过二分查找算法来解决。在每次迭代中,根据中间元素与目标值的大小关系,更新搜索范围,直到找到第一个大于目标值的元素或确定不存在这样的元素。
相关文章:
Javascript算法——二分查找
1.数组 1.1二分查找 1.搜索索引 开闭matters!!![left,right]与[left,right) /*** param {number[]} nums* param {number} target* return {number}*/ var search function(nums, target) {let left0;let rightnums.length-1;//[left,rig…...
node-sass/vendor/linux-x64-72 : Error: EACCES: permission denied, mkdir
npm i --unsafe-perm node-sassgithub解决问题...
uniapp-uniapp + vue3 + pinia 搭建uniapp模板
使用技术 ⚡️uni-app, Vue3, Vite, pnpm 📦 组件自动化引入 🍍 使用 Pinia 的状态管理 🎨 tailwindcss - 高性能且极具灵活性的即时原子化 CSS 引擎 😃 各种图标集为你所用 🔥 使用 新的 <script setup> …...
深度学习的一些数学基础
数学基础 万丈高楼平地起 怎么说呢,学的数二对于这些东西还是太陌生了,而且当时学的只会做题,不知道怎么使用/(ㄒoㄒ)/~~ 所以记下来一些不太清楚的前置知识点,主要来自《艾伯特深度学习》,书中内容很多,…...
自由学习记录(13)
服务端常见的“资源” 在服务端,常见的“资源”指的是服务端提供给客户端访问、使用、处理或操作的各种数据和功能。根据不同类型的服务和应用场景,服务端的资源种类可以非常广泛。以下是一些常见的服务端资源类型: 1. 文件和静态资源 网页…...
低代码可视化-uniapp海报可视化设计-代码生成
在uni-app中,海报生成器通常是通过集成特定的插件或组件来实现的,这些插件或组件提供了生成海报所需的功能和灵活性。我们采用了lime-painter海报组件。lime-painter是一款canvas海报组件,可以更轻松地生成海报。它支持通过JSON及Template的方…...
一次使用LD_DEBUG定位问题的经历
在实际工作中,当遇到段错误,我们会很容易的想到这是非法访问内存导致的,比如访问了已经释放的内存,访问数据越界,尝试写没有写权限的内存等。使用gdb进行调试,查看出异常的调用栈,往往可以定位到…...
数据库安全:如何进行数据库安全审计?
数据库安全:如何进行数据库安全审计? 数据库安全审计是保障数据库安全的重要手段之一,可以帮助企业及时发现潜在的安全风险并采取相应的措施。以下是进行数据库安全审计的步骤和方法: 一、确定审计目标 在进行数据库安全审计之前,首先需要确定审计的目标。这可能包括以…...
【Python】基础语法错误和异常
在Python中,语法错误和异常是两个常见的问题。下面对它们进行简要介绍。 1.语法错误 (Syntax Error) 语法错误是指代码的语法不符合Python的语言规则。当Python解释器读取程序代码时,如果发现语法不正确,就会抛出语法错误。这种错误通常在代…...
获取每个页面的元素,并写入json
获取每个页面的元素,并写入json 想法:如何去记住每个页面的元素,如何实现不同页面的导航,如何从主页面遍历每一个页面的每一个元素 1.创建数据结构存储 2.树状图正好是我们想要的结构体:创建树状图结构体 3.记录每个页…...
【ShuQiHere】深入解析数字电路中的锁存器与触发器
深入解析数字电路中的锁存器与触发器 🤖🔌 在数字电路设计中,**锁存器(Latch)和触发器(Flip-Flop)**是实现时序逻辑的基本元件。它们能够存储状态,是构建复杂数字系统的关键。本文将…...
【学习AI-相关路程-mnist手写数字分类-python-硬件:jetson orin NX-自我学习AI-基础知识铺垫-遇到问题(1) 】
【学习AI-相关路程-mnist手写数字分类-python-硬件:jetson orin NX-自我学习AI-基础知识铺垫-遇到问题(1) 】 1、前言2、先行了解(1)学习基础知识-了解jetson orin nx 设备(2)学习python&AI…...
数据轻松上云——Mbox边缘计算网关
随着工业4.0时代的到来,工厂数字化转型已成为提升生产效率、优化资源配置、增强企业竞争力的关键。我们凭借其先进的边缘计算网关与云平台技术,为工厂提供了高效、稳定的数据采集与上云解决方案。本文将为您介绍Mbox边缘计算网关如何配合明达云平台&…...
ifftshift函数
ifftshift 原理 将频域数据移回时域的函数。它通常与 fftshift 配合使用,后者用于将时域数据移动到频域中心。 而ifftshift所作的事正好相反,将频谱恢复到能量集中在两端(或四个角)上,接着就可以做逆傅里叶变换了 具…...
vue3 + ts + element-plus 二次封装 el-dialog
实现效果: 组件代码:注意 style 不能为 scoped <template><el-dialog class"my-dialog" v-model"isVisible" :show-close"false" :close-on-click-modal"false" :modal"false"modal-class&…...
MySQL9.0安装教程zip手动安装(Windows)
本章教程,主要介绍如何在Windows上安装MySQL9.0,通过zip方式进行手动安装。 一、下载MySQL压缩包 下载地址:https://downloads.mysql.com/archives/community/ 二、解压MySQL压缩包 将下载好的压缩包,进行解压缩,并且将…...
如何在浏览器中查看格式化的 HTML?
问题描述 我需要这个 HTML 页面在我的浏览器中显示格式化后的信息。我只是将文件存储在本地驱动器上。我需要将文件上传到服务器才能将其作为 HTML 查看,还是可以在本地查看?如在屏幕截图中看到的,它当前显示相同的 HTML 代码。我尝试搜索&am…...
浅谈计算机存储体系和CPU缓存命中
一、计算机存储 一般关于计算机存储体系分为三层 ①三级缓存/寄存器 大多数寄存器只有四字节到八字节,只用于读取很小的数据;三级缓存是为了方便CPU读取内存中数据而存在的 ②内存————数据结构就是在内存中管理数据 ③硬盘————数据库/文件就…...
ES操作:linux命令
查询数据库所有索引 没有密码 curl -X GET "http://localhost:9200/_cat/indices?v" 有密码 curl -u elastic:my_password -X GET "http://localhost:9200/_cat/indices?v" 删除索引 curl-X DELETE "http://localhost:9200/index_XXX" 不…...
Java使用原生HttpURLConnection实现发送HTTP请求
Java 实现发送 HTTP 请求,系列文章: 《Java使用原生HttpURLConnection实现发送HTTP请求》 《Java使用HttpClient5实现发送HTTP请求》 《SpringBoot使用RestTemplate实现发送HTTP请求》 1、HttpURLConnection 类的介绍 HttpURLConnection 是 Java 提供的…...
QWEN-AUDIO开箱即用指南:无需conda/pip,纯Docker镜像启动
QWEN-AUDIO开箱即用指南:无需conda/pip,纯Docker镜像启动 想体验一下“有温度”的AI语音合成吗?以前你可能需要折腾Python环境、安装各种依赖、处理版本冲突,光是配置环境就能劝退一大半人。今天,我要分享一个完全不同…...
二叉树面试送分题|力扣101对称+226翻转(递归极简写法,手写无压力)
兄弟们!二叉树面试中,有两道“送分题”必须拿捏——力扣101.对称二叉树和力扣226.翻转二叉树。这两道题难度不高,核心都能用递归轻松解决,代码简洁、逻辑直观,新手练一遍就能记住,面试手写直接加分…...
H5端微信登录实战:从配置到用户信息获取的全流程解析
1. 为什么需要H5端微信登录? 每次开发新项目时,用户注册环节总是让人头疼。传统的账号密码注册方式,不仅流程繁琐,还经常遇到用户忘记密码的问题。我在去年开发一个电商H5项目时,就发现超过60%的用户流失都发生在注册…...
AI如何悄悄改变你的日常生活?5个你已离不开的AI应用场景
AI如何悄悄改变你的日常生活?5个你已离不开的AI应用场景 清晨被智能闹钟以最舒适的渐强音量唤醒,通勤路上听着音乐App精准推荐的歌单,晚上回家对着冰箱说出想吃的菜谱——这些场景中隐藏的AI技术,早已像水电一样成为生活基础设施。…...
PCB拼板工艺全解析:从设计到生产的核心要点
1. PCB拼板的核心价值与必要性PCB拼板是电子工程中一项看似简单却极为关键的工艺环节。作为一名从业十年的硬件工程师,我处理过上千款PCB设计,深刻体会到合理拼板对生产效率和成本控制的影响。简单来说,拼板就是将多块相同或不同的PCB按照特定…...
小白卖家的“时间困境”:为什么我每天忙得要死,却不出单?
忙碌不是努力,是方法出了问题。入行跨境电商三个月了。从零到日出百单,这条路我算是走通了。但回想起来,最让我后怕的,不是刚开始没单的那段日子,而是中间那段“看起来很忙”的日子。每天从早忙到晚,电脑上…...
基于中点电位平衡的光伏NPC三电平逆变器并网仿真研究:额定功率100kW、直流电压750V的M...
光伏NPC三电平逆变并网仿真 [1]包含中点电位平衡,额定功率100kW,直流电压750V。 光伏阵列参数已设定,采用mppt算法(扰动观察法); [2]主电路采用二极管钳位型NPC逆变器; 采用电压电流双闭环控制&…...
我是如何突然把论文‘AI率’从85%降到6%?这6大保姆级教程,秒懂!
AI如今已成为大部分同学论文“提速神器”,但是不合规过度使用AI往往会导致论文AI率超标。如果你还在写初稿,一定要合理利用AI,让AI来搭建初稿框架,寻找灵感,整理数据,切勿过度使用AI。 今年知网,…...
嵌入式系统内存泄漏防护与实战解决方案
1. 内存泄漏的危害与现状分析在嵌入式系统开发中,内存泄漏堪称"隐形杀手"。我经历过一个真实案例:某通信设备在现网运行三个月后频繁重启,最终定位是某个看似无害的日志处理函数每次调用泄漏512字节内存。这个案例让我深刻认识到&a…...
SRS (Simple Realtime Server) 实战:从SFU到大规模互动直播架构
1. SRS与SFU:互动直播的基石架构 第一次接触SRS时,我被它简洁的配置方式惊艳到了。这个看似轻量级的服务器,竟然能支撑起我们平台日均百万级的直播流量。作为选择性转发单元(SFU),SRS的核心价值在于它解决了…...
