题目
整数数组 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 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
例:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
方法:二分查找
因为要求使用时间复杂度为 O(log n) 的算法,所以采用二分查找
- left 和 right 分别表示左右指针,left 指向数组的首部,right 指向数组的尾部
- 循环直至 left 位于 right 的右侧
- mid 表示此时中点
- 若 mid 下标对应的元素值等于目标值 target,那么找到目标值,返回此时下标
- 因为此时的数组 nums 是通过一次旋转得到的,那么从中间分开后,两侧至少有一侧是升序排列的。若左边新数组的首部元素值 nums[0] 小于尾部元素值 nums[mid],及左边数组是升序排列的,那么可以通过判断目标值 target 是否位于该区间内,缩小查找范围
- 若目标值 target 存在于 [[nums[0], nums[mid]),那么目标值在该区间内,缩小范围,将右指针 right 指向中点左移一步后的位置 mid - 1
- 若目标值 target 不存在于 [nums[0], nums[mid]),那么目标值在右边新数组中,缩小范围,将左指针 left 指向中点右移一步后的位置 mid + 1
- 否则,右边数组是升序排列的,那么可以通过判断目标值 target 是否位于该区间内,缩小查找范围
- 若目标值 target 存在于 (nums[mid], nums[len(nums)-1]],那么目标值在该区间内,缩小范围,将左指针 left 指向中点右移一步后的位置 mid + 1
- 若目标值 target 不存在于 (nums[mid], nums[len(nums)-1]],那么目标值在左边新数组中,缩小范围,将右指针 right 指向中点左移一步后的位置 mid - 1
- 若不存在目标值 target,返回 -1
class Solution(object):
def search(self, nums, target):
left, right = 0, len(nums)-1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
if nums[0] <= nums[mid]:
if nums[0] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
else:
if nums[mid] < target <= nums[len(nums)-1]:
left = mid + 1
else:
right = mid - 1
return -1
相关知识
-
二分查找:
首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
参考
代码相关:https://leetcode.cn/problems/search-in-rotated-sorted-array/solution/sou-suo-xuan-zhuan-pai-xu-shu-zu-by-leetcode-solut/
二分查找:https://baike.baidu.com/item/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE/10628618?fr=aladdin
网友评论