35. 搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
思考
二分模板题
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)
#[left,right)
while left<right:
mid = int((left+right)/2)
if nums[mid] > target:
right = mid
elif nums[mid] < target:
left = mid + 1
else:
return mid
return left
BM21 旋转数组的最小数字(有重复数字)
思考
剑指offer上原题。数组划分为2个区间,二分搜索逐渐逼近最小值。遇到无法判断区间时,需要顺序逐个查找。
class Solution:
def minNumberInRotateArray(self , nums: List[int]) -> int:
# write code here
left = 0
right = len(nums)-1
mid = 0
while nums[left]>=nums[right]:
if right-left == 1:
return nums[right]
mid = int((left+right)/2)
if nums[left] == nums[right] and nums[left] == nums[mid]:
res = nums[left]
for i in range(left+1,right+1):
if nums[i] < res:
res = nums[i]
return res
if nums[mid] >= nums[left]:
left = mid
elif nums[mid] <= nums[right]:
right = mid
return nums[left]
- 搜索旋转排序数组 (无重复数字搜索指定target)
整数数组 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) 的算法解决此问题。
思考
根据mid值判断是左有序 还是 右有序。在有序的区间内进行二分查找。
class Solution:
def search(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)-1
#[left,right]
mid = -1
while left<=right:
mid = int((left+right)/2)
if nums[mid] == target:
return mid
if nums[mid] >= nums[left]:
#左有序
if target >= nums[left] and target < nums[mid]:
# 二分
right = mid - 1
else:
left = mid + 1
else:
#右有序
if target > nums[mid] and t arget <= nums[right]:
left = mid + 1
else:
right = mid -1
return -1
153.寻找旋转排序数组中的最小值(无重复)
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
思考
比有重复的要简单一点。两种方法。
方法1:剑指offer版本,比较容易理解:划分为2个区间,逐渐逼近结果。
class Solution:
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums)-1
mid = 0
while nums[left] > nums[right]:
if right - left == 1:
return nums[right]
mid = (left+right)//2
if nums[mid] >= nums[left]:
left = mid
elif nums[mid] <=nums[right]:
right = mid
return nums[0]
方法2:leetcode官方题解。
在二分查找的每一步中,左边界为 low,右边界为 high,区间的中点为 pivot,最小值就在该区间内。我们将中轴元素 nums[pivot] 与右边界元素 nums[high] 进行比较,可能会有以下的三种情况:
class Solution:
def findMin(self, nums: List[int]) -> int:
left = 0
right = len(nums)-1
mid = 0
while left < right:
mid = (left+right)//2
if nums[mid] < nums[-1]:
right = mid
else:
left = mid + 1
return nums[left]
34. 在排序数组中查找元素的第一个和最后一个位置
给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
思考
划分为2个区间 <target 和 >=target 来寻找左边界。
右边界通过寻找targe+1的左边界-1来代替。优雅
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
def getRightBorder(nums, target):
left = 0
right = len(nums)-1
#right_border = -2
while left<=right:
mid = int((left+right)/2)
if nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return right
def getLeftBorder(nums, target):
left = 0
right = len(nums)-1
#left_border = -2
while left<=right:
mid = int((left+right)/2)
if nums[mid] < target:
left = mid + 1
else:
right = mid - 1
#left_border = right
return left
left_border = getLeftBorder(nums, target)
#right_border = getRightBorder(nums,target)
right_border = getLeftBorder(nums, target+1) - 1
if left_border == len(nums) or nums[left_border] != target:
return [-1,-1]
else:
return [left_border,right_border]
标签:二分,right,target,nums,int,mid,查找,大厂,left
From: https://www.cnblogs.com/forrestr/p/18290406