壹 ❀ 引

本来今天(2021.4.7)的每日一题是81. 搜索旋转排序数组 II,但今天工作很忙,下班人基本累个半死,题目别说按照二分法的思路做不出来,连题解看了会都没法沉下心去看,不过得到的信息是,本题属于另一道的变体,而且若先了解另一题,对于本题会有较大的帮助,想了想就还是先记录之前的题,题目来自LeetCode33. 搜索旋转排序数组,题目难度同样是中等,题目描述如下:

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 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

今天就熬个夜先记录和理解本题吧,明天再把升级版的题目再补回来。

贰 ❀ 简单分析与二分法

JS的同学可能看到此题,本能想到的就是findIndex了,不过要是用这种来解题,本身就没什么意义了,所以这种投机取巧的做法就不说了,对于算法也没太大提升,我们直接介绍二分法做法。

我在JS leetcode 寻找旋转排序数组中的最小值 题解分析,你不得不了解的二分法一文中,有简单提及二分法,而且比较巧的是,这道题也是旋转数组。关于二分法查找的优点是,每次条件判断后总能舍弃掉一半的元素,从而大大加快查找的效率,二分法的时间复杂度是O(logn),我们先上一个查找目标元素的二分法模板:

// 查找目标值二分法模板
function binarySearch(arr, target) {
var low = 0;
var high = arr.length - 1;
while (low <= high) {
var mid = Math.floor((low + high) / 2);
if (target === arr[mid]) {
return mid;
} else if (target > arr[mid]) {
low = mid + 1;
} else {
high = mid - 1;
};
};
return -1;
};

而对于本题来说,较为难受的是数组虽然是有序数组,但是一个经过旋转的有序数组,我们不知道在哪个点进行了旋转,所以一般的二分法在这行不通。

对于常规二分法,我们是根据目标值与mid对比,从而确定目标值在mid的左侧或者右侧(或者运气好直接相等找到了),从而不断缩小范围。但事实上,对于旋转的有序数组依旧有规律可循。

我们以数组[1,2,3,4,5]为例,我们要找到3,它可能存在旋转情况如下:

如上图,第一行为为旋转,下面四行为此数组可能旋转的所有情况,我们找出mid,根据与nums[0]的大小对比,可以得知:

  1. 若mid<nums[0],那么mid在右侧有序序列,比如[2,3,4]
  2. 若mid>=nums[0],那么mid在左侧有序序列,比如[3,4,5]注意,为什么是>=后面会解释

这样我们就已经对于区域做了一次划分,但既然是二分法,自然得舍弃掉一半的元素,此时就得依赖target了,判断依据其实很简单。

假设我们的数组是[5,1,2,3,4]找3,我们先得知有序序列在右侧,也就是[2,3,4],我们将这个范围理解为[mid,end],那么只要target>mid&&target<=end,那就说明3一定在右侧有序序列中,左边的[5,1]可以直接舍弃。

接下来我们可以调整左侧边界为mid+1继续搜索,为什么加1呢?因为如果mid===target已经返回了,能走到这一步自然mid不会相等,下次调整边界自然可以舍弃掉,用图表示这个过程如下:

有同学可能就想到,你这样解释太过于理想了,如果target在无序那边呢?其实也不冲突,我们还是假设[5,1,2,3,4]中找1。

很明显由于mid<5,所以有序部分在右侧,但因为target并不满足target>mid&&target<=end,因此右边界调整为mid-1,于是我们舍弃了右边部分,得到了[5,1]

接下来怎么办?当然还是重复判断哪边为有序部分,哪边不是,我们同样还是找到mid,也就是5,由于此时mid>=nums[0],也就是5>=5,因此mid在左侧有序部分,所以得到了有序部分[5]以及无序部分[1],哎,到这里你是不是知道了为什么是>=了?找出有序部分的目的,其实就是为了方便我们利用target>mid && target<=end(假设有序有右侧)来决定放弃哪一部分,如果你的数组不是有序的,target>mid&&target<=end这个公式你根本没法满足。

那么上面这个过程用图就是下面这样:

解释的够清楚了,直接上代码:

/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var search = function (nums, target) {
let l = 0;
let r = nums.length - 1; while (l <= r) {
const mid = Math.floor((l + r) / 2);
if (nums[mid] === target) {
return mid;
};
if (nums[mid] >= nums[l]) {
//target 在 [l, mid] 之间
if (target >= nums[l] && target < nums[mid]) {
r = mid - 1;
} else {
//target 不在 [l, mid] 之间
l = mid + 1;
};
} else {
// [mid, r]有序
// target 在 [mid, r] 之间
if (target > nums[mid] && target <= nums[r]) {
l = mid + 1;
} else {
// target 不在 [mid, r] 之间
r = mid - 1;
}
}
}
return -1;
};

总结下解题的核心,第一点,根据mid与nums[0](第一位是可变的,所以其实是nums[左边界])决定哪一边是有序序列,对有序序列套用target>mid && target<=r从而得知target在不在有序序列这一边,不在自然在无序那一边,继续循环上述步骤,找到最终答案。

真的累了,2点了....睡觉。这题就说到这里了。

嗯....图片貌似有点大,确实困了...就这样吧。

JS Leetcode 33. 搜索旋转排序数组题解,图解旋转数组中的二分法的更多相关文章

  1. Java实现 LeetCode 33 搜索旋转排序数组

    33. 搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值, ...

  2. 力扣Leetcode 33. 搜索旋转排序数组

    33. 搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值, ...

  3. [LeetCode]33. 搜索旋转排序数组(二分)

    题目 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个目 ...

  4. [leetcode] 33. 搜索旋转排序数组(Java)

    33. 搜索旋转排序数组 说实话这题我连题都没有看懂....真是醉了 二分,没意思,直接交了- - https://www.jiuzhang.com/solutions/search-in-rotat ...

  5. leetcode 33. 搜索旋转排序数组 及 81. 搜索旋转排序数组 II

    33. 搜索旋转排序数组 问题描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定 ...

  6. LeetCode 33 - 搜索旋转排序数组 - [二分]

    假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个目标值, ...

  7. LeetCode 33 搜索旋转排序数组

    题目: 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值,如果数组中存在这个 ...

  8. [LeetCode] 33. Search in Rotated Sorted Array 在旋转有序数组中搜索

    Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...

  9. LeetCode 33——搜索旋转排序数组

    1. 题目 2. 解答 2.1. 方法一 直接进行二分查找,在判断查找方向的时候详细分类. 当 nums[mid] < target 时, 若 nums[left] <= nums[mid ...

  10. leetcode 33搜索旋转排序数组

    暴力解法:O(n) 想办法用二分查找Ologn

随机推荐

  1. SpringMVC06——数据绑定——2021-05-09

    数据绑定介绍 在执行程序时,SpringMVC会根据客户端请求参数的不同, 将请求信息中的信息以一定的方式转换并绑定到控制器类的方法参数中. 在数据绑定过程中,SpringMVC框架会通过数据绑定组件 ...

  2. [转帖]MySQL 官方出品,比 mydumper 更快的多线程逻辑备份工具-MySQL Shell Dump & Load

    MySQL 官方出品,比 mydumper 更快的多线程逻辑备份工具-MySQL Shell Dump & Load - 知乎 (zhihu.com) ​ 目录 收起 什么是 MySQL Sh ...

  3. K8S Only IPV6的创建过程之二 完整版

    K8S Only IPV6的创建过程之二 完整版 整体过程 1. 阿里云新增一台虚拟机, 开通IPV6.与数据库,redis实现物理隔离. 并且进行环境基本处理,安装kubeadm等组件. 2. ku ...

  4. 使用Grafana + jmx 监控 kafka3.5 的过程

    使用Grafana + jmx 监控 kafka3.5 的过程 摘要 周五一边进行数据库监控, 同时想着部署一套监控系统. 能够监控一下kafka等中间件 结果不想自己遇到了很多坑. 下午有同事语音告 ...

  5. [转帖]技术分享 | 国产麒麟 arm 上编译安装 xtrabackup8

    原创 发布于 2022-07-19 13:29:29 3220 举报 作者:王向 爱可生 DBA 团队成员,负责公司 DMP 产品的运维和客户 MySQL 问题的处理.擅长数据库故障处理.对数据库技术 ...

  6. [转帖]数据库系列之TiDB存储引擎TiKV实现机制

    TiDB存储引擎TiKV是基于RocksDB存储引擎,通过Raft分布式算法保证数据一致性.本文详细介绍了TiKV存储引擎的实现机制和原理,加深对TiDB底层存储架构的理解. 1.TiDB存储引擎Ti ...

  7. [转帖]使用 TiUP 部署运维 TiDB 线上集群

    https://docs.pingcap.com/zh/tidb/stable/tiup-cluster 本文重在介绍如何使用 TiUP 的 cluster 组件,如果需要线上部署的完整步骤,可参考使 ...

  8. [转帖]linux服务之tuned

    https://www.cnblogs.com/createyuan/p/5701650.html RHEL/CentOS 在 6.3 版本以后引入了一套新的系统调优工具 tuned/tuned-ad ...

  9. 【转帖】Meta 推出大型语言模型 LLaMA,比 GPT3.5 性能更高

    https://finance.sina.com.cn/wm/2023-02-28/doc-imyihfvp8075151.shtml ChatGPT 的爆火使得大家对 AI 进行了深度的讨论,大厂们 ...

  10. [转帖]耗时几个月,终于找到了JVM停顿十几秒的原因

    https://www.cnblogs.com/codelogs/p/16060792.html   原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介# 最近我们系 ...