【leetcode-Python】-二分搜索-81 Search in Rotated Sorted Array II

目录

 

题目链接

题目描述

示例

解决思路一

解决思路一Python实现

解决思路二

解决思路二Python代码

 相关题目


题目链接

81. Search in Rotated Sorted Array II

题目描述

在可能包含重复元素的旋转有序数组中搜索一个target,如果target在数组中被找到,返回True,否则返回False。

示例

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

输出:True

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

输出:False

解决思路一

1、在有重复元素的旋转有序数组中找到旋转点pivot,即第一个小于nums[-1]的元素(可参考【leetcode-Python】- 二分搜索 - 154 Find Minimum in Rotated Sorted Array II中的“进一步扩展”部分)。

2、比较target和nums[-1]的大小,如果target小于nums[-1],说明target在右排序数组中,下一步在[pivot,len(nums)-1]范围内搜索target;如果target大于nums[-1],说明target在左排序数组中,下一步在[0,pivot-1]范围内进行搜索,搜索过程可参考模板一【Leetcode-Python】-二分搜索模板汇总与相关题目。如果target等于nums[-1],说明target一定可以在nums中找到,因此直接返回True。

时间复杂度:最优情况下(数组中所有元素都不相等)时间复杂度为O(logN),最差情况下(数组元素都相等并且不等于target)时间复杂度为O(N)

空间复杂度:O(1)

解决思路一Python实现

class Solution:
    def search(self, nums: List[int], target: int) -> bool:
        if(len(nums) == 0):
            return False
        # get the pivot
        left = 0
        right = len(nums)-1
        while(left < right):
            mid = (left + right) // 2
            if(nums[mid] > nums[right]): #说明pivot在mid的右侧,且mid不可能是pivot
                left = mid + 1    
            elif(nums[mid] < nums[right]) : #pivot有可能是mid,也可能在mid 的左侧。
                right = mid
            else: # nums[mid] == nums[right] #pivot不确定在mid的左侧还是右侧。
                if(nums[right] < nums[right - 1]): #在这个条件下nums[right]就是pivot,如果不做这一步判断直接通过right -= 1缩小范围的话有可能把pivot越过。
                    break #跳出循环
                right -= 1 #如果nums[right]不是pivot,需要将right向左移动一位,缩小搜索范围。
        pivot = right
        if(target > nums[-1]): #target可能在左排序序列
            left,right = 0,pivot-1
        elif(target < nums[-1]): #target可能在右排序序列
            left,right = pivot,len(nums)-1
        else:
            return True
        while(left <= right): #这一部分参考模板一
            mid = (left + right) // 2
            if(nums[mid] == target):
                return True
            elif(nums[mid] < target):
                left = mid + 1
            else:
                right = mid - 1
        return False
            
        
                

解决思路二

总体上仍然采用二分搜索的思路,但和上一个思路还是有些差别:在这个方法中,直接根据nums[mid]和target在旋转有序数组中的位置(左排序序列还是右排序序列)来收缩搜索区间,不需要先判断旋转点的位置。考虑循环的维持条件、搜索区间收缩的条件和边界的更新方式这几个写二分搜索时要注意的关键点,由于是在数组中寻找某元素是否存在,优先考虑模板一,模板详见【Leetcode-Python】-二分搜索模板汇总与相关题目。循环的维持条件为left <= right,对应边界更新方式是left = mid + 1或right = mid - 1。搜索区间收缩条件根据nums[mid]和target在旋转有序数组中的位置确定,nums[mid]和target(如果存在)在旋转有序数组中的位置包括三种情况:

(1)nums[mid]在左排序序列(nums[mid] > nums[right]),target在右排序序列中存在(target <= nums[right])。这种情况下更新left = mid + 1。

(2)nums[mid]在右排序序列(nums[mid] < nums[right]),target在左排序序列中存在(target > nums[right])。这种情况下更新right = mid - 1。

(3)target和nums[mid]同时在左排序序列或右排序序列。  由于两个序列都是升序序列,这种情况下根据target和nums[mid]的大小比较结果来收缩搜索区间。

在情况(2)中,由于target > nums[right],因此target不可能在右排序序列中存在,那么如果target存在,只会在左排序序列中存在。其次认为target == nums[right]属于target在右排序序列的情况,不一定能够保证target在左排序序列中一定存在。因此在第二种情况中“target在左排序序列中存在”的代码表达为target > nums[right]。

当nums[mid] == nums[right]时不确定nums[mid]在左排序序列还是在右排序序列,此时令right -= 1缩小搜索范围,在不影响搜索结果的条件下继续循环。

时间复杂度:最优情况下(数组中所有元素都不相等)时间复杂度为O(logN),最差情况下(数组元素都相等并且不等于target)时间复杂度为O(N)

空间复杂度:O(1)

但是当nums中元素非常多时,解决思路二相较于解决思路一要快一些,因为解决思路一需要先寻找pivot再缩小搜索区间,解决思路二则略过了寻找pivot这一步。

解决思路二Python代码

class Solution:
    def search(self, nums: List[int], target: int) -> bool:
        if(len(nums) == 0):
            return False
        left = 0
        right = len(nums)-1
        while(left <= right):
            mid = (left + right) // 2
            if(nums[mid] == target): 
                return True
            if(nums[mid] == nums[right]):#如果nums[mid] == nums[right],不确定nums[mid]在左排序区间还是右排序区间,在这种情况下让right左移一位以在不影响结果的前提下继续循环
                right -= 1
                continue
            if(nums[mid] > nums[right] and target <= nums[right]):#nums[mid]在左排序序列 并且 target在右排序序列(如果target < nums[right],target在右排序序列,如果target == nums[right],target也在右排序序列,这里两种情况放到一起考虑,
#因为收缩搜索区间的方式都是left = mid + 1)
                left = mid + 1
            elif(nums[mid] < nums[right] and target > nums[right]): #nums[mid]在右排序序列,target在左排序序列
                right = mid - 1
            else: #target和nums[mid]同时在左排序序列或右排序序列,但两个子序列都是升序序列
                if(target > nums[mid]):
                    left = mid + 1
                else:
                    right = mid - 1
        return False

        

 

 相关题目

【leetcode-Python】- 二分搜索 - 154 Find Minimum in Rotated Sorted Array II

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值