搜索旋转排序数组
整数数组 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 。
这里数组中的值互不相同需要注意。
题目分析
由于原数组有序,旋转后,旋转位置的左右两边的序列都是升序,因此,可以使用二分查找。
我们可以判断target和mid以及左右两边界的关系来确定有序区域。
- 如果mid >= nums[left],则满足下图左边的情况,此时,判断target的位置
- 如果 nums[left] <= target < nums[mid],则将范围缩小至[left,mid-1];
- 其他情况在[mid+1,right]中寻找;
- 如果mid < nums[left],则满足下图右边的情况,此时,判断target的位置
- 如果 nums[mid] < target <= nums[right],则将范围缩小至[mid+1,right]
- 其他情况在[left,mid-1]搜索。
满足度量函数的性质,注意和边界判断时,都需要等号。
代码实现
class Solution: def search(self, nums: List[int], target: int) -> int: n = len(nums) left,right = 0,n-1 while left <= right: mid = (left+right)//2 if nums[mid] == target: return mid if nums[mid] >= nums[left]: if nums[left] <= target < nums[mid]: right = mid - 1 else: left = mid + 1 else: if nums[mid] < target <= nums[right]: left = mid + 1 else: right = mid - 1 return -1
搜索旋转排序数组II
本题为上一题的扩展,当数组中存在重复元素时,如何查找target。
此时可能存在重复元素分散在旋转中心两端的情况,例如:[2,2,2,2,6,0,1,2]。此时,可能出现nums[left] = nums[mid] = nums[right]的情况,导致无法判断哪个区间是有序的。
因此,对于这种情况,我们需要将二分区间进行压缩。
代码实现
class Solution: def search(self, nums: List[int], target: int) -> int: n = len(nums) if n == 1: return nums[0] == target left,right = 0,n-1 while left <= right: mid = (left+right)//2 if nums[mid] == target: return True if nums[left] == nums[mid] and nums[right] == nums[mid]: left += 1 right -= 1 elif nums[mid] >= nums[left]: if nums[left] <= target < nums[mid]: right = mid - 1 else: left = mid + 1 else: if nums[mid] < target <= nums[right]: left = mid + 1 else: right = mid - 1 return False