🥋二分查找(旋转数组&山脉数据)
2022-5-20
| 2023-5-15
0  |  阅读时长 0 分钟
type
status
password
date
slug
summary
category
URL
tags
icon

旋转数组

算法原理

旋转数组的算法原理可以参照 二分查找(有序数组),但是拥有比 二分查找(有序数组)更复杂的 IsBlue。下面分别从最小值和目标值介绍 如何判断旋转数组的 IsBlue
 

2.寻找旋转排序数组中的最小值(153 - 中)

题目描述

整数数组 nums 按升序排列,数组中的值 互不相同,并按上述情形进行了多次旋转 。请你找出并返回数组中的 最小元素
示例 :

二分查找

我们考虑数组中的最后一个元素 nums[-1]:在最小值右侧的元素(不包括最后一个元素本身),它们的值一定都严格小于 nums[-1];而在最小值左侧的元素,它们的值一定都严格大于 num[-1]。因此,我们可以根据这一条性质,通过二分查找的方法找出最小值。
  • nums[mid]<nums[-1],这说明nums[mid]是最小值右侧的元素。
  • nums[mid]>nums[-1],这说明nums[mid]是最小值左侧的元素。
notion image
横轴表示数组元素的下标,纵轴表示数组元素的值。图中标出了最小值的位置,是我们需要查找的目标。
综上:我们可以参照 二分查找基本原理 的模板,修改 IsBlue() 的条件。使得左侧>nums[-1],右侧≤nums[-1]。
代码实现:

3.寻找旋转排序数组中的最小值II(154 - 难)

题目描述

整数数组 nums 按升序排列,数组中的值 可能存在重复值 。返回数组中的 最小元素 。同 剑指 Offer 11. 旋转数组的最小数字
示例 :

二分查找

思路与上题不同的是数组中可能含有重复值,由于重复元素的存在,会出现nums[mid]=nums[-1]的情况,此时我们并不能确定 nums[mid] 究竟在最小值的左侧还是右侧,因此我们不能莽撞地忽略某一部分的元素。面对这种情况,我们可以不断缩小 nums 最右侧的区间,从 nums[-1] 缩小到nums[-2]nums[-3]nums[-4]
notion image
代码实现:

4.搜索旋转排序数组(33 - 中)

题目描述

整数数组 nums 按升序排列,数组中的值 互不相同 。给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
示例 :

方法一:先寻找最值,然后将旋转数组分成两个有序数组

最简单的做法, 找到 「153. 寻找旋转排序数组中的最小值」的索引,由此可以将数组分为升序的两段。根据 nums[0] 与 target 的关系判断 target 在左段还是右段,再对升序数组进行二分查找即可。 同样的思路可以解决「1095. 山脉数组中查找目标值」,即先找到山脉数组的峰顶「852. 山脉数组的峰顶索引」, 通过峰顶将山脉数组分为两段有序的数组,接下来就可以在有序数组中查找目标值了。

直接二分查找

对于旋转数组,我们无法直接根据 nums[mid] 与 target 的大小关系来判断 target 是在 mid的左边还是右边,因此需要「分段讨论」。
  • 首先通过nums[mid]和nums[0]比较,判断旋转点在mid的左侧还是右侧,进而确定有序区间在mid左边还是右边。.
  • 再确定目标元素target在哪边!,根据target、mid、边缘点(最左右两侧元素)即可判断target与在mid的左侧还是右侧。
这种情况同样可以套用 二分查找模板只不过 判断条件(IsBlue)复杂些,代码实现

5.搜索旋转排序数组II(81 - 中)

题目描述

旋转数组 nums可能存在重复值 。请你编写一个函数来判断给定的目标值 target 是否存在于数组 nums 中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。
示例 :

思路33题+154题

33题基本相同,不同的是含有重复元素;154题也是含有重复元素的题目。所以本题可以参考上述两道题目。
 
时间复杂度:对于这种含重复元素的二分查找问题,最坏时间复杂度O(n),即整个数组都是同一个数,最好时间复杂度O(nlogn)。
代码实现:

山脉题目

notion image
notion image
山脉题目与旋转数组题目相似,但是又有些不同。旋转数据的左边一定大于右边(递增数据);山脉数据的左边不一定大于右边。旋转数据的查找条件需要与边界值进行比较,山脉数据的查找条件是

8.山脉数组的峰顶索引(852 - 易)

题目描述

符合下列属性的数组 arr 称为 山脉数组 :
  • arr.length >= 3
  • 存在 i(0 < i < arr.length - 1)使得:
    • arr[0] < arr[1] < ... <arr[i-1] < arr[i]
    • arr[i] > arr[i+1] > ... > arr[arr.length - 1]
给你由整数组成的山脉数组 arr ,返回任何满足 arr[0] < arr[1] < ... <arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i 。
示例 :

枚举

我们可以对数组 进行一次遍历。当我们遍历到下标 i 时,如果有 ,那么 就是我们需要找出的下标。更简单地,我们只需要让 满足 即可。在遍历的过程中,我们最先遍历到的满足 的下标 一定也满足

二分查找

  • arr[mid] > arr[mid + 1]:那么mid在最大值的右侧,right=mid
  • arr[mid] < arr[mid + 1]:那么mid在最大值的左侧,left=mid
  • arr[mid] = arr[mid+1]:这种情况不存在,所以可以添加到任意其他情况

9.山脉数组中查找目标值(1095 - 难)

题目描述:给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。如果不存在这样的下标 index,就请返回 -1。
示例 :

先寻找最值,然后将旋转数组分成两个有序数组

最简单的做法, 即先找到山脉数组的峰顶「852. 山脉数组的峰顶索引」, 通过峰顶将山脉数组分为两段有序的数组,接下来就可以在有序数组中查找目标值了。
 
 
 
  • 二分查找
  • 数组
  • 二分查找(有序)哈希表
    Loading...
    目录