博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二分法05:搜索旋转排序数组
阅读量:3951 次
发布时间:2019-05-24

本文共 4076 字,大约阅读时间需要 13 分钟。

搜索旋转排序数组

整数数组 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

以二分搜索为基本思路

在这里插入图片描述

可以发现的是,我们将数组从中间分开成左右两部分的时候,一定有一部分的数组是有序的。拿示例来看,我们从 6 这个位置分开以后数组变成了 [4, 5, 6,7] 和 [0, 1, 2] 两个部分,其中左边 [4, 5, 6,7] 这个部分的数组是有序的,其他也是如此。

这启示我们可以在常规二分查找的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分查找的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:

简要来说:

nums[0] <= nums[mid] 时,[0, mid] 不包含旋转,即是有序数组 。

  • 如果nums[0] <= target <= nums[mid] 时 ,即target 在 [left, mid] 中,应该将右边界范围缩小至right = mid
  • 否则 target 在 [mid+1, right ] 中,应该将左边界范围缩小至left = mid +1

nums[mid] < nums[0] 时,[mid, -1] 不包含旋转,即是有序数组 。

  • 如果nums[mid] < target <= nums[-1] 时 ,即target 在 [mid+1, right ] 中,应该将左边界范围缩小至left = mid +1
  • 否则 target 在**[left, mid]** 中,应该将右边界范围缩小至right = mid
class Solution(object):    def search(self, nums, target):        """        :type nums: List[int]        :type target: int        :rtype: int        """        if not nums:            return -1        left ,right = 0, len(nums) -1        while left< right:            mid = left+(right-left)//2            if nums[0] <= nums[mid]: # 左边有序                if  nums[0] <= target <= nums[mid]:                    right = mid                else:                    left = mid +1            else:                    # 右边有序                if nums[mid] < target <= nums[-1]:                    left = mid +1                else:                    right = mid        if left==right and nums[left]==target:            return left        else:            return -1

复杂度分析

时间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n 为 nums \textit{nums} nums 数组的大小。整个算法时间复杂度即为二分查找的时间复杂度 O ( log ⁡ n ) O(\log n) O(logn)

空间复杂度: O ( 1 ) O(1) O(1) 。我们只需要常数级别的空间存放变量。

搜索旋转排序数组 II

这是 搜索旋转排序数组 的延伸题目,本题中的 nums 可能包含重复元素。

已知存在一个按非降序排列的整数数组 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,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。

给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。

示例 1:

输入:nums = [2,5,6,0,0,1,2], target = 0输出:true

示例 2:

输入:nums = [2,5,6,0,0,1,2], target = 3输出:false

思路:二分查找

对于数组中有重复元素的情况,二分查找时可能会有 a [ l ] = a [ mid ] = a [ r ] a[l]=a[\textit{mid}]=a[r] a[l]=a[mid]=a[r] ,此时无法判断区间 [ l , mid ] [l,\textit{mid}] [l,mid]和区间 [ mid + 1 , r ] [\textit{mid}+1,r] [mid+1,r] 哪个是有序的。

例如 nums = [ 3 , 1 , 2 , 3 , 3 , 3 , 3 ] \textit{nums}=[3,1,2,3,3,3,3] nums=[3,1,2,3,3,3,3] target = 2 \textit{target}=2 target=2,首次二分时无法判断区间 [ 0 , 3 ] [0,3] [0,3] 和区间 [ 4 , 6 ] [4,6] [4,6] 哪个是有序的。

对于这种情况,我们只能将当前二分区间的左边界加一,相当于去掉重复的干扰项,然后在新区间上继续二分查找。

class Solution(object):    def search(self, nums, target):        """        :type nums: List[int]        :type target: int        :rtype: int        """        if not nums:            return False        if len(nums)==1:            return nums[0]==target        left ,right = 0, len(nums) -1        while left< right:            mid = left+(right-left)//2            if nums[left] == nums[mid] and nums[mid]== nums[right]:                left +=1            elif nums[left] <= nums[mid]: # 左边有序                if  nums[left] <= target <= nums[mid]:                    right = mid                else:                    left = mid +1            else:                    # 右边有序                if nums[mid] < target <= nums[-1]:                    left = mid +1                else:                    right = mid        if left==right and nums[left]==target:            return True        else:            return False

复杂度分析

时间复杂度: O ( n ) O(n) O(n),其中 n 是数组 nums \textit{nums} nums 的长度。最坏情况下数组元素均相等且不为 target \textit{target} target,我们需要访问所有位置才能得出结果。

空间复杂度:O(1)。

参考

力扣(LeetCode) (leetcode-cn.com)]

《画解剑指 Offer 》

转载地址:http://tdyzi.baihongyu.com/

你可能感兴趣的文章
Requests实践详解&& python通过连接开启https的elasticsearch7 服务器
查看>>
ES查询流程源码解析
查看>>
ldaps与ldap over TLS
查看>>
jvm为什么把-Xms和-Xmx的值设置成一样
查看>>
2021-01-21对map进行key或者value排序
查看>>
ConcurrentHashMap 1.7和1.8的区别
查看>>
阻塞锁与自旋锁
查看>>
【面试官:select语句和update语句分别是怎么执行的
查看>>
scala学习之安装问题
查看>>
LDAP常见错误码
查看>>
linux yum安装rpm包出现问题
查看>>
idea编译报错类似xxx.java:[85,65] 错误: 找不到符号
查看>>
ArrayList复制
查看>>
idea打开项目时,文件左下角显示橙色J
查看>>
SQL注入
查看>>
linux中ldconfig的使用介绍
查看>>
ldap适合入门学习
查看>>
ldap学习参考博客
查看>>
linux学习之source命令与alias(别名)使用
查看>>
MYSQL常用查询
查看>>