一. LeetCode 153.寻找旋转排序数组最小值
1. 问题描述
给你一个整数数组 nums ,和一个整数 target 。
该整数数组原本是按升序排列,但输入时在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
2. 问题分析
最直观的方法 return min(nums)
, 时间复杂度为O(n),直接下一题, 看样子好像没什么题,但显然这样就失去寻优的乐趣。
题目上说是排序数组,因此我们能够联想二分查找法,但是由于是旋转后的数组所以我们需要修改条件。
在这样的数组中,因为只旋转一次,因此可以分为这样三段:
我们只要找到inflection point就能找到最小值。
3. 算法
- 找到中间元素索引 mid;
- 如果 中间元素 大于 第一个元素 , 那么应该向 mid 右边 寻找;
- 如果 中间元素 小于 第一个元素, 那么应该向 mid 左边 寻找;
- 满足
nums[mid] > nums[mid+1]
此时nums[mid+1]
为最小值
或者nums[mid] < nums[mid-1]
此时nums[mid]
为最小值
4. 代码(Python)
class Solution:
def findMin(self, nums: List[int]) -> int:
if len(nums) == 1:
return nums[0]
left, right = 0, len(nums)-1
if nums[right] > nums[left]: ## 处理没有旋转的特殊情况
return nums[left]
while left <= right:
mid = (left + right) // 2
if nums[mid] > mid[mid+1]:
return nums[mid+1]
if nums[mid] < nums[mid-1]:
return nums[mid]
if nums[mid] > nums[0]:
left = mid + 1
else:
right = mid - 1
二. LeetCode 33.搜索旋转排序数组
1. 问题描述
给你一个整数数组 nums ,和一个整数 target 。
该整数数组原本是按升序排列,但输入时在预先未知的某个点上进行了旋转。(例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
2. 问题分析
我们可以在常规二分搜索的时候查看当前 mid 为分割位置分割出来的两个部分 [l, mid] 和 [mid + 1, r] 哪个部分是有序的,并根据有序的那个部分确定我们该如何改变二分搜索的上下界,因为我们能够根据有序的那部分判断出 target 在不在这个部分:
- 如果 [l, mid - 1] 是有序数组,且 target 的大小满足[nums[l],nums[mid]),则我们应该将搜索范围缩小至 [l, mid - 1],否则在 [mid + 1, r] 中寻找。
- 如果 [mid, r] 是有序数组,且 target 的大小满足 (nums[mid+1],nums[r]],则我们应该将搜索范围缩小至 [mid + 1, r],否则在 [l, mid - 1] 中寻找。
3. 代码(Python)
class Solution:
def search(self, nums: List[int], target: int) -> int:
if not nums:
return -1
l, r = 0, len(nums)-1
while l <= r:
mid = (l+r) // 2
if nums[mid] == target:
return mid
if nums[mid] >= nums[l]:
if nums[l] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
else:
if nums[mid] < target <= nums[r]:
l = mid + 1
else:
r = mid - 1
return -1