剑指 Offer 11. 旋转数组的最小数字 面试题 10.03. 搜索旋转数组 二分查找

剑指 Offer 11. 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,
输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。  
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0

解题思路

二分查找,注意当numbers[mid]==numbers[right]时无法判断mid是在左排序还是右排序中,所以解决方案是 right=right-1 缩小判断范围。对于 right=right-1,只需证明每次执行此操作后,旋转点 x 仍在 [left,right]区间内即可。(可以理解为:因为相等,所以删掉一个留下一个,我们在剩下区间搜索,仍可以搜索到删除的那个元素值。)

class Solution:
    def minArray(self, numbers: List[int]) -> int:
        left, right = 0, len(numbers) - 1 
        while left< right:
            mid = (left + right) // 2 
            if numbers[mid]>numbers[right]:
                left = mid + 1 
            elif numbers[mid]<numbers[right]:
                right = mid 
            else:
                right -= 1 
        return numbers[left]

面试题 10.03. 搜索旋转数组

搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。
请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,
返回索引值最小的一个。
示例1:
 输入: arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 5
 输出: 8(元素5在该数组中的索引)
示例2:
 输入:arr = [15, 16, 19, 20, 25, 1, 3, 4, 5, 7, 10, 14], target = 11
 输出:-1 (没有找到)
提示:
arr 长度范围在[1, 1000000]之间

解题思路

先使用二分查找找出数组最小值的索引,然后将其转为升序的数组,再使用二分查找目标值
注意如果数组的最后一个数和第一个数相同,则去掉最后一个数,保证数组最后一个数和第一个数不同

class Solution:
    def search(self, arr: List[int], target: int) -> int:
        # 如果数组的最后一个数和第一个数相同,则去掉最后一个数,保证数组最后一个数和第一个数不同
        while len(arr) > 1 and arr[-1] == arr[0]:
            arr.pop() 
        # 数组长度
        length = len(arr) 
        # 先找出最小值的索引
        left, right = 0, len(arr) - 1 
        while left<right:
            mid = (left + right) // 2 
            if arr[mid]>arr[right]:
                left = mid + 1 
            elif arr[mid]<arr[right]:
                right = mid 
            else:
                right -= 1 
        # left表示数组中最小值的索引
        # 将数组中前面的升序部分拼接到数组后面,使得数组从left~right部分为递增序列
        right = left + length - 1 
        # 如果target比数组最小的还要小,那么肯定不存在
        if target<arr[left]: return -1 
        # 二分查找target
        while left<right:
            mid = (left + right) >> 1
            # mid%length表示在原数组的位置,因为实际原数组并没有改变,只是将其索引改变了
            # 由于当有多个相同元素时需要返回索引最小的,所以当arr[mid%length]>=target时只能取right = mid
            # 直到left==right截止(向下取整)
            if arr[mid%length]>=target:
                right = mid 
            else:
                left = mid + 1 
        if arr[left%length]==target:
            return left%length
        else:
            return -1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值