LeetCode-33. 搜索旋转排序数组【数组 二分查找】
- 题目描述:
- 解题思路一:二分查找。1.找哨兵节点(nums[0]或nums[-1])可以确定nums[mid]位于前一段或后一段有序数组中。2. 就是边界left和right的变换,具体看代码。
- 解题思路二:二分查找,注意在闭区间[0, n-2]上面查找!
- 解题思路三:蓝色说明是nums[mid] > target 应该改变right = mid
题目描述:
整数数组 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) 的算法解决此问题。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:
输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:
输入:nums = [1], target = 0
输出:-1
提示:
1 <= nums.length <= 5000
-104 <= nums[i] <= 104
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-104 <= target <= 104
解题思路一:二分查找。1.找哨兵节点(nums[0]或nums[-1])可以确定nums[mid]位于前一段或后一段有序数组中。2. 就是边界left和right的变换,具体看代码。
需要注意的是,二分的写法有很多种,所以在判断 target 大小与有序部分的关系的时候可能会出现细节上的差别。
class Solution:def search(self, nums: List[int], target: int) -> int:if not nums:return -1l, r = 0, len(nums) - 1while l <= r:mid = (l + r) // 2if nums[mid] == target:return midif nums[0] <= nums[mid]:if nums[0] <= target < nums[mid]:r = mid - 1else:l = mid + 1else:if nums[mid] < target <= nums[len(nums) - 1]:l = mid + 1else:r = mid - 1return -1
时间复杂度:O(logn)
空间复杂度:O(1)
解题思路二:二分查找,注意在闭区间[0, n-2]上面查找!
class Solution:def findMin(self, nums: List[int]) -> int:left, right = -1, len(nums) - 1 # 开区间 (-1, n-1)while left + 1 < right: # 开区间不为空mid = (left + right) // 2if nums[mid] < nums[-1]: # 蓝色right = midelse: # 红色left = midreturn rightdef lower_bound(self, nums: List[int], left: int, right: int, target: int) -> int:while left + 1 < right: # 开区间不为空mid = (left + right) // 2# 循环不变量:# nums[left] < target# nums[right] >= targetif nums[mid] < target:left = mid # 范围缩小到 (mid, right)else:right = mid # 范围缩小到 (left, mid)return right if nums[right] == target else -1def search(self, nums: List[int], target: int) -> int:i = self.findMin(nums)if target > nums[-1]:left, right = -1, i # 左段else:left, right = i - 1, len(nums) # 右段return self.lower_bound(nums, left, right, target)
时间复杂度:O(logn)
空间复杂度:O(1)
解题思路三:蓝色说明是nums[mid] > target 应该改变right = mid
class Solution:def search(self, nums: List[int], target: int) -> int:def is_blue(i: int) -> bool:end = nums[-1]if nums[i] > end:return target > end and nums[i] >= targetelse:return target > end or nums[i] >= targetleft, right = -1, len(nums) - 1 # 开区间 (-1, n-1)while left + 1 < right: # 开区间不为空mid = (left + right) // 2if is_blue(mid): # 蓝色right = midelse: # 红色left = midreturn right if nums[right] == target else -1
时间复杂度:O(logn)
空间复杂度:O(1)