二分搜索
首先掌握一个套路
- 长度为0的情况
- while循环,双指针
- 写判断条件
- 兜底情况
其次,面试时的三问:
- 数组有无重复元素
- 是否有序
- 是否有负值
相关题目
- 旋转有序数组的搜索:记住无论怎么旋,有一部分会是有序的
153. 寻找旋转排序数组中的最小值
【无重复元素】
def findMin(self, nums: List[int]) -> int:
if len(nums) == 0:
return -1
n =len(nums)
l,r = 0 ,n-1
while l +1 < r:
if nums[r] > nums[l]:
return nums[l]
mid = l + (r - l) // 2
if nums[mid] >= nums[l]:
l = mid + 1
else:
r = mid
return nums[l] if nums[l] < nums[r] else nums[r]
154. 寻找旋转排序数组中的最小值 II
【有重复元素】
def findMin(self, nums: List[int]) -> int:
if len(nums) == 0:
return -1
n =len(nums)
l,r = 0 ,n-1
while l +1 < r:
if nums[r] > nums[l]:
return nums[l]
mid = l + (r - l) // 2
if nums[mid] > nums[l]:
l = mid + 1
elif nums[mid] == nums[l]:
while l < mid and nums[l] == nums[mid]:
l += 1
else:
r = mid
return nums[l] if nums[l] < nums[r] else nums[r]
旋转数组有无重复元素是很常见的问题,有重复元素通常会体现在端端相等,就需要多个判断并处理
面试题 10.03. 搜索旋转数组
搜索旋转数组。给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次了,次数不详。请编写代码找出数组中的某个元素,假设数组元素原先是按升序排列的。若有多个相同元素,返回索引值最小的一个。
先来看个错误的做法:
def search(self, nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
n =len(nums)
l,r = 0 ,n-1
while l +1 < r:
mid = l + (r-l) // 2
if nums[l] < nums[mid]:
if nums[l] <= target and target <= nums[mid]:
r = mid
else:
l = mid
elif nums[l] > nums[mid]:
if nums[mid] <= target and target <= nums[r]:
#if nums[l] <= target or target <= nums[mid]:
l = mid
else :
r = mid
else :
if nums[l] != target:
l += 1
else:
r = mid
if nums[l] == target:
return l
if nums[r] == target:
return r
return -1
错在哪?[5,5,5,1,2,3,4,5] 5,对于这种类型的例子会错误。
原因在于 nums[l] > nums[mid]时,右部分是有序的,我想看target是否在右边。对于上述例子,5在右边确实有,但因为有重复元素,左部分同样有。要返回最小索引,就必须全部在左部分判断。
改成注释的部分,即可。或者加上一个判断语句,如果是第一个元素就是target,返回。
9.供暖器
对于每个房子,找到离它最近的供暖器,记录下距离。找出所有距离的最大值即可。
74.搜索二维矩阵
记住有序的二维矩阵,看左对角,上方小于右边大于。
面试题03. 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
- 解法一:排序后找, O ( n l o g n ) O(nlogn) O(nlogn)
- 解法二:哈希表。用一个字典记录。空间换时间,遍历一遍即可。
- 解法三:用数组的性质,nums[i] = i,继续;nums[i] != i时,比较 nums[i] 与 nums[nums[i]],如果相等,说明这个元素是重复的。如果不等,交换位置,把nums[i]放到其有序的位置上,这样就可以找到重复的。
287. 寻找重复数
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
def findDuplicate(self, nums: List[int]) -> int:
l = 1
r = len(nums) - 1
while l < r:
count = 0
mid = l + ( r - l ) // 2
for i in nums :
if i <= mid:
count += 1
if count <= mid:
l = mid + 1
else :
r = mid
return l
要注意与上一题的不同,这边是1到n。,具体差别在哪里还需要思考(坑)
另一种解法,还没领悟。
def findDuplicate(nums):
# The "tortoise and hare" step. We start at the end of the array and try
# to find an intersection point in the cycle.
slow = 0
fast = 0
while True:
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast:
break
finder = 0
while True:
slow = nums[slow]
finder = nums[finder]
if slow == finder:
return slow
可以确认,如果是0-n-1同样不行。因为nums[0] = 0时,永远在原地踏步。