04、JS实现:用⼆分法思想实现搜索旋转排序数组(一步一步剖析,很详细)

news2024/9/22 4:23:30

搜索旋转排序数组

  • Ⅰ、搜索旋转排序数组:
    • 1、题目描述:
    • 2、解题思路:
    • 3、实现代码:
  • Ⅱ、小结:

Ⅰ、搜索旋转排序数组:

1、题目描述:

给你⼀个升序排列的整数数组 nums ,和⼀个整数 target 。
假设按照升序排序的数组在预先未知的某个点上进⾏了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个⽬标值,则返回它的索引,否则返回 -1 。
示例 1:
输⼊:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输⼊:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输⼊:nums = [1], target = 0
输出:-1

提示:
1 <= nums.length <= 5000
-10^4 <= nums[i] <= 10^4 nums 中的每个值都 独⼀⽆⼆ nums 肯定会在某个点上旋转
-10^4 <= target <= 10^4

2、解题思路:

题⽬要求时间复杂度为 logn,因此基本就是⼆分法了。 这道题⽬不是直接的有序数组,不然就是 easy 了。
⾸先要知道,我们随便选择⼀个点,将数组分为前后两部分,其中⼀部分⼀定是有序的。

具体步骤:
我们可以先找出 mid,然后根据 nums[mid] 来判断,mid 是在有序的部分还是⽆序的部分;
假如 nums[mid] ⼩于 nums[start],则mid ⼀定在右边有序部分。
假如 nums[mid] ⼤于等于 nums[start], 则 mid ⼀定在左边有序部分。
注意等号的考虑 然后我们继续判断 target 在哪⼀部分, 我们就可以舍弃另⼀部分了;
我们只需要⽐较 target 和有序部分的边界关系就⾏了。
⽐如:mid 在右侧有序部分,即 [mid, end] 那么我们只需要判断 target >= nums[mid] && target <= nums[end] 就能知道 target 在右侧有序部分,我们就可以舍弃左边部分了(start = mid + 1), 反之亦然。


可能存在的问题:
其一、为什么 nums[mid] 小于 nums[start],则右边一定有序,而 nums[mid] ⼤于等于 nums[start],则
左边一定有序?
答:因为整数数组 nums 是升序排列的,且在未知的某个点上进⾏了旋转,那么其 nums[end] < nums[start] 
是一定成立的;因此若 nums[mid] >= nums[start],就说明 nums[start] 到 nums[mid-1] 是升序的,因
此就可以说左边是有序部分;同理,若 nums[mid] < nums[start],就说明 nums[mid+1] 到 nums[end] 是
升序的;

3、实现代码:

其一、代码为:


const searchPermutation = (nums, target) => {
  // 时间复杂度:O(logn)
  // 空间复杂度:O(1)
  let start = 0
  let end = nums.length - 1
  while (start <= end) {
    // 此时的 ((end - start) >> 1) 操作是除法操作,但是会向下取整;
    const mid = start + ((end - start) >> 1)

    // 若 nums[mid] === target,则直接将 mid 值返回(即:目标值);
    if (nums[mid] === target) return mid

    if (nums[mid] >= nums[start]) {
      // ⚠ 注意这⾥的等号;
      // 若 nums[mid] >= nums[start] 成立,就表示 [start, mid] 有序;
      if (target >= nums[start] && target <= nums[mid]) {
        // 表示:target 在 [start, mid] 之间;
        // 其实 target 不可能等于 nums[mid], 但是为了对称,还是加上了等号;
        end = mid - 1
      } else {
        // 表示:target 不在 [start, mid] 之间;
        start = mid + 1
      }
    } else {
      // 若 nums[mid] >= nums[start] 不成立,就表示 [mid, end] 有序;
      if (target >= nums[mid] && target <= nums[end]) {
        // 表示:target 在 [mid, end] 之间;
        start = mid + 1
      } else {
        // 表示:target 不在 [mid, end] 之间;
        end = mid - 1
      }
    }
  }
  // 若 while(start <= end){} 没有返回值,就说明:数组中不存在这个 target(即:⽬标值);
  return -1
}

// 此时的返回值为:7;
searchPermutation([6, 7, 8, 1, 2, 3, 4, 5], 5)

// 此时的返回值为:-1;
searchPermutation([13, 14, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 16)


```//代码的执行过程如下所示:


    执行  searchPermutation([6, 7, 8, 1, 2, 3, 4, 5], 5)  函数后代码执行的过程:
    
第一次循环:start 为 0,end 为 7,target 为 5,nums 着眼于 nums[0] 到 nums[7];
    start     end   mid     target          nums[mid]        nums[start]
      0   <=   7     3	      5      !==    nums[3]=1    <   nums[0]=6

    start   end   mid      nums[mid]         target         nums[end]
      0      7     3       nums[3]=1    <=     5      <=    nums[7]=5
    
    start
    3+1=4


第二次循环:start 为 4,end 为 7,target 为 5,nums 着眼于 nums[4] 到 nums[7];
    start     end   mid     target          nums[mid]        nums[start]
      4   <=   7     5	      5      !==    nums[5]=3    >=  nums[4]=2

    start   end   mid      nums[start]       target         nums[mid]
      4      7     5       nums[4]=2    <=     5      >     nums[5]=3
    
    start
    5+1=6


第三次次循环:start 为 6,end 为 7,target 为 5,nums 着眼于 nums[6] 到 nums[7];
    start     end   mid     target          nums[mid]        nums[start]
      6   <=   7     6	      5      !==    nums[6]=4    >=  nums[6]=4

    start   end   mid      nums[start]       target         nums[mid]
      6      7     6       nums[6]=4    <=     5      >     nums[6]=4
    
    start
    6+1=7


第四次次循环:start 为 7,end 为 7,target 为 5,nums 着眼于 nums[7] 到 nums[7];
    start     end   mid     target          nums[mid]
      7   <=   7     7	      5      ===    nums[7]=5

   return 7(即:返回 mid 值,此时函数的最终输出结果就是 7);


    执行  searchPermutation([13, 14, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 16)  函数后代码执行的过程:

第一次循环:start 为 0,end 为 15,target 为 16,nums 着眼于 nums[0] 到 nums[15];
    start     end   mid     target          nums[mid]        nums[start]
      0   <=   15    7	      16     !==    nums[7]=4    <   nums[0]=13

    start   end   mid      nums[mid]         target         nums[end]
      0      15    7       nums[7]=4    <=     16     >     nums[15]=12
    
    end
    7-1=6


第二次循环:start 为 0,end 为 6,target 为 16,nums 着眼于 nums[0] 到 nums[6];
    start     end   mid     target          nums[mid]         nums[start]
      0   <=   6     3	      16     !==    nums[3]=18   >=   nums[0]=13

    start   end   mid      nums[start]         target         nums[mid]
      0      6     3       nums[0]=13     <=     16     <=    nums[3]=18
    
    end
    3-1=2


第三次循环:start 为 0,end 为 2,target 为 16,nums 着眼于 nums[0] 到 nums[2];
    start     end   mid     target          nums[mid]         nums[start]
      0   <=   2     1	      16     !==    nums[1]=14   >=   nums[0]=13

    start   end   mid      nums[start]         target         nums[mid]
      0      2     1       nums[0]=13     <=     16     <=    nums[1]=18
    
    end
    1-1=0
    

第四次次循环:start 为 0,end 为 0,target 为 16,nums 着眼于 nums[0] 到 nums[0];
    start     end   mid     target           nums[mid]         nums[start]
      0   <=   0     0	      16      !==    nums[0]=13   >=   nums[0]=13

    start   end   mid      nums[start]         target         nums[mid]
      0      0     0       nums[0]=13     <=     16      >    nums[0]=13

    start
    0+1=1


第五次次循环:start 为 1,end 为 0,target 为 16,nums 着眼于 nums[1] 到 nums[0];
    start     end
      1    >   0 

   return -1(即:返回 -1 的值,此时函数的最终输出结果就是 -1,说明:数组中不存在 16 (即:⽬标值,target));
   

其二、截图为:

// 调用的函数为:searchPermutation([6, 7, 8, 1, 2, 3, 4, 5], 5),此时的返回值为:7;

在这里插入图片描述

// 调用的函数为:searchPermutation([13, 14, 17, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], 16),此时的返回值为:-1;

在这里插入图片描述

Ⅱ、小结:

其一、哪里有不对或不合适的地方,还请大佬们多多指点和交流!
其二、若有转发或引用本文章内容,请注明本博客地址(直接点击下面 url 跳转) https://blog.csdn.net/weixin_43405300,创作不易,且行且珍惜!
其三、有兴趣的话,可以多多关注这个专栏(Vue(Vue2+Vue3)面试必备专栏)(直接点击下面 url 跳转):https://blog.csdn.net/weixin_43405300/category_11525646.html?spm=1001.2014.3001.5482

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

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

相关文章

【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串

送给大家一句话&#xff1a; 充满着欢乐与斗争精神的人们&#xff0c;永远带着欢乐&#xff0c;欢迎雷霆与阳光。 —— 赫胥黎 滑动窗口精通 前言Leetcode 30. 串联所有单词的子串题目描述算法思路 Leetcode 76. 最小覆盖子串题目描述算法思路 Thanks♪(&#xff65;ω&#xf…

产品推荐 | 基于 Zynq UltraScale+ XCZU27DR的 FACE-RFSoC-C高性能自适应射频开发平台

一、产品概述 FACE-RFSOC-C自适应射频开发平台&#xff0c;是FACE系列新一代的产品。 平台搭载有16nm工艺的Zynq UltraScale™ RFSoC系列主器件。该器件集成数千兆采样RF数据转换器和ARM Cortex-A53处理子系统和UltraScale可编程逻辑&#xff0c;是一款单芯片自适应射频平台。…

风力发电模型Windpowerlib概述与入门

Windpowerlib 是一个提供了一系列函数和类的库&#xff0c;用于计算风力涡轮机的功率输出。它最初是 feedinlib&#xff08;风能和光伏&#xff09;的一部分&#xff0c;但后来被分离出来&#xff0c;以建立一个专注于风能模型的社区。 这个库的主要目的是简化风力涡轮机的能量…

Vue3 + Vite + TS + Element-Plus + Pinia项目(3)--新建路由

1、在src文件夹下新建router文件夹后&#xff0c;创建index.ts文件 2、具体如下 import { createRouter, createWebHashHistory } from vue-routerconst router createRouter({history: createWebHashHistory(),routes: [{path: "/index",component: () > impor…

红黑树进阶:正向与反向迭代器的实现及map、set的封装实践

文章目录 一、引言二、红黑树迭代器设计1、迭代器的基本概念和分类2、正向迭代器设计a.迭代器结构定义b.迭代器的 与 -- 3、反向迭代器设计a.反向迭代器的必要性b.反向迭代器的实现要点 4、红黑树封装迭代器 三、使用红黑树实现Map四、红黑树实现Set五、细节理解1、 typname的使…

JAVA学习笔记19(面向对象编程)

1.面向对象编程 1.1 类与对象 1.类与对象的概念 ​ *对象[属性]/[行为] ​ *语法 class cat {String name;int age; }main() {//cat1就是一个对象//创建一只猫Cat cat1 new Cat();//给猫的属性赋值cat1.name "123";cat1.age 10; }​ *类是抽象的&#xff0c;…

【Redis系列】那有序集合为什么要同时使用字典和跳跃表

面试官&#xff1a;听说你精通Redis&#xff0c;那我就考考你吧 面试官&#xff1a;不用慌尽管说&#xff0c;错了也没关系&#x1f60a;。。。 以【面试官面试】的形式来分享技术&#xff0c;本期是《Redis系列》&#xff0c;感兴趣就关注我吧❤️ 面试官&#xff1a;你说说Re…

个人可以做知识付费网站吗

个人可以做知识付费网站吗 个人能够做学问付费网站吗&#xff1f;答案是肯定的&#xff01;如今个人做学问付费网站并不需求太多的资金和技术支持&#xff0c;我们只需求购置一台效劳器或虚拟主机&#xff0c;然后在该主机空间上搭建一个WordPress网站&#xff0c;最后运用带有…

商家如何自己零成本免费制作点餐小程序项目完整源码

现在点餐小程序成为餐饮店的标配&#xff0c;顾客只要扫码&#xff0c;即可进入小程序点餐。顾客付款后&#xff0c;后厨自动打印出订单并开始制作。整个过程非常方便流畅&#xff0c;甚至还可以免去收银&#xff08;或服务&#xff09;人员。那么&#xff0c;这种餐饮小程序要…

类和对象三部曲(one)

都说C语言是面向过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用来逐步解决问题。 拿洗衣服来举例&#xff0c;C关注的是一个过程&#xff1a; 那么C是什么呢&#xff1f; 面向对象的编程语言。 面向对象对象指什么&#xff1f; 象棋里的对象么&#xff1f;…

JavaScript学习第二天

1.学习JavaScript高级语法目的 降低后续对于前端框架学习难度 1.局部变量与全局变量 1.局部变量: 在函数体内部通过var声明的变量 1.局部变量特点: 局部变量只能在当前函数体内使用&#xff0c;不能 在函数体外使用 2.全局变量 在script标签下直接…

AI之Suno:Suno V3的简介、安装和使用方法、案例应用之详细攻略

AI之Suno&#xff1a;Suno V3的简介、安装和使用方法、案例应用之详细攻略 目录 Suno AI的简介 1、特点与改进&#xff1a; Suno AI的安装和使用方法 1、第一步&#xff0c;让国产大模型—ChatGLM4帮我写一个提示词 2、第二步&#xff0c;将提示词交给Suno v3&#xff0c;…

LDL^H分解求逆矩阵与MATLAB仿真(Right-Looking)

通过分解将对称正定厄米特矩阵分解成下三角矩阵L和对角矩阵D来求其逆矩阵 目录 前言 一、LDL^H基本算法 二、LDL^H Right-Looking算法 三、D矩阵求逆 四、L矩阵求逆 五、A矩阵求逆 六、计算量分析 七、MATLAB仿真 八、参考资料 总结 前言 在线性代数中&#xff0c;LDL…

如何在Ubuntu系统使用Docker搭建MongoDB结合内网穿透实现公网连接

文章目录 前言1. 安装Docker2. 使用Docker拉取MongoDB镜像3. 创建并启动MongoDB容器4. 本地连接测试5. 公网远程访问本地MongoDB容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Linux Ubuntu系统使用Docker快速部署Mon…

企业如何选择一个开源「好」项目?

开源 三句半​​​​​​​ 需求明确是关键 风险考量要周全 开源虽好不白捡 别忘合规&#xff01; 显然&#xff0c;开源已成为一股不可阻挡的洪流&#xff0c;企业拥抱开源&#xff0c;积极参与开源项目不仅是响应技术潮流的必然选择&#xff0c;更是实现自身技术创新、市场拓…

GETSHELL方法总结上

渗透的总步骤 1.信息收集找到弱漏洞 2.漏洞挖掘 漏洞验证 3.有一定权限 getshell 4.提权后---渗透 5.内网渗透】 前后台拿shell方法汇总 接下来我们实操一波dedecms也就是织梦cms 如果你们的靶场是空白的 可能是php版本 我们修改为5.2 可能是源码问题 我们不要急着上传…

【vue核心技术实战精讲】1.6 - 1.8 VUE 指令 (中)

文章目录 前言 本节内容1、v-on使用v-on好处效果 2、事件修饰符2.1、按键码 (<font color red>已废弃&#xff0c;不用研究)示例效果 3、v-for 列表渲染示例效果 前言 上节,我们学习了 Vue指令之v-text 、 v-html、v-if 、v-show、v-bind 点击进入上一节 本节内容 Vue…

【Linux基础】ubuntu虚拟机配置及原理

一、虚拟机 虚拟机&#xff08;Virtual Machine&#xff0c;VM&#xff09;是一种软件实现的计算机系统&#xff0c;它在物理计算机上模拟了一个完整的计算机硬件环境&#xff0c;包括处理器、内存、存储设备和网络接口等。通过虚拟机&#xff0c;用户可以在单个物理计算机上同…

二叉搜索树(二叉排序树,二叉查找树)(附图详解+代码实现+应用分析)

最近学习了有关搜索二叉树的相关知识&#xff0c;在此特意将该知识进行总结分享&#xff0c;希望对大家有所帮助。 文章目录 一.二叉搜索树1.1二叉搜索树的概念1.2二叉搜索树的操作&#xff08;含思路分析代码实现&#xff09;1.2.1二叉搜索树的查找&#xff08;递归实现看最后…

RocketMQ学习笔记:零拷贝

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、零拷贝技术1.1、什么是零拷贝1.2、mmap()1.3、Java中的零拷贝 1、零拷贝技术 1.1、什么是零拷贝 使用传统的IO&#xff0c;从硬盘读取数据然后发送到网络需要经过四个步骤。 通过DMA复…