class Solution:
def search(self, nums: List[int], target: int) -> int:
# 基础二分查找
low = 0
high = len(nums) - 1
while low <= high:
mid = low + (high-low) // 2
if nums[mid] > target:
high = mid - 1
elif nums[mid] < target:
low = mid + 1
else:
return mid
return -1
class Solution:
def nextGreatestLetter(self, letters: List[str], target: str) -> str:
if target >= letters[-1]:
return letters[0]
low = 0
high = len(letters) - 1
while low <= high:
mid = low + (high - low) // 2
if letters[mid] > target:
# 判断是不是第一个
if mid == 0 or letters[mid-1] <= target:
return letters[mid]
high = mid - 1
else:
low = mid + 1
return
class Solution:
def search(self, nums: List[int], target: int) -> int:
# 二分查找,以 mid 分界,一定有一半是有序数组
size = len(nums)
l, r = 0, size - 1
while l <= r:
mid = l + (r - l) // 2
if nums[mid] == target:
return mid
# 判断左边是否是有序数组
if nums[l] <= nums[mid]:
if nums[l] <= target and target <= nums[mid]:
r = mid - 1
else:
l = mid + 1
# 右边有序
else:
if nums[mid] <= target and target <= nums[r]:
l = mid + 1
else:
r = mid -1
return -1
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
# 二分查找目标值第一个和最后一个
n = len(nums)
l, r = 0, n-1
res = [-1, -1]
# 查找起始位置
while l <= r:
mid = l + (r - l) // 2
if nums[mid] < target:
l = mid + 1
elif nums[mid] > target:
r = mid -1
else:
# 注意需要判断 mid == 0
if mid == 0 or nums[mid] > nums[mid - 1]:
res[0] = mid
break
else:
r = mid - 1
# 查找结束位置
l, r = 0, n-1
while l <= r:
mid = l + (r - l) // 2
if nums[mid] < target:
l = mid + 1
elif nums[mid] > target:
r = mid -1
else:
# 注意需要判断 mid == n-1
if mid == n-1 or nums[mid+1] > nums[mid]:
res[1] = mid
break
else:
l = mid + 1
return res
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
n = len(nums)
l, r = 0, n-1
while l <= r:
mid = l + (r - l) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
r = mid - 1
else:
l = mid + 1
return l
class Solution:
def mySqrt(self, x: int) -> int:
# 二分查找
l, r = 0, x
while l <= r:
mid = l + (r - l) // 2
tmp = mid * mid
if tmp == x:
return mid
elif tmp > x:
r = mid - 1
else:
l = mid + 1
return l - 1
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
m = len(matrix)
n = len(matrix[0])
# # 两次二分查找
# col = [i[0] for i in matrix]
# l, r = 0, m-1
# while l <= r:
# mid = l + (r - l) // 2
# if col[mid] == target:
# return True
# elif col[mid] > target:
# r = mid - 1
# else:
# l = mid + 1
# row_index = l - 1
# l, r = 0, n-1
# while l <= r:
# mid = l + (r - l) // 2
# if matrix[row_index][mid] == target:
# return True
# elif matrix[row_index][mid] > target:
# r = mid -1
# else:
# l = mid + 1
# return False
# 一次二分查找
l, r = 0, m * n -1
while l <= r:
mid = l + (r - l) // 2
# mid 转换为二维下标
tmp = matrix[mid // n][mid % n]
if tmp == target:
return True
elif tmp > target:
r = mid -1
else:
l = mid + 1
return False
81. 搜索旋转排序数组 II
class Solution:
def search(self, nums: List[int], target: int) -> bool:
# 二分查找
# 对比「搜索旋转排序数组」题目,可能会出现 nums[l] = nums[mid] = nums[r] 的情况,只能 l++ & r-- 排除干扰项继续查找
n = len(nums)
l, r = 0, n-1
while l <= r:
mid = l + (r-l) // 2
if nums[mid] == target:
return True
# 这里分开排除干扰项
elif nums[l] == nums[mid]:
l += 1
elif nums[r] == nums[mid]:
r -= 1
# 左边有序
elif nums[l] < nums[mid]:
if nums[l] <= target and target <= nums[mid]:
r = mid - 1
else:
l = mid + 1
# 右边有序
else:
if nums[mid] <= target and target <= nums[r]:
l = mid + 1
else:
r = mid - 1
return False
153. 寻找旋转排序数组中的最小值
class Solution:
def findMin(self, nums: List[int]) -> int:
print(nums)
n = len(nums)
l, r = 0, n-1
# while l <= r:
# mid = l + (r - l) // 2
# if r - l == 1:
# return min(nums[l], nums[r])
# # 整体有序
# if nums[l] <= nums[mid] and nums[mid] <= nums[r]:
# return nums[l]
# # 左边有序
# if nums[l] < nums[mid]:
# l = mid
# # 右边有序
# else:
# r = mid
while l < r:
mid = l + (r - l) // 2
if nums[mid] > nums[r]:
l = mid + 1
else:
r = mid
return nums[l]
154. 寻找旋转排序数组中的最小值 2
class Solution:
def findMin(self, nums: List[int]) -> int:
# 和 left 判断
# 当left到right为非递减数组,此时跟left比较,按理说(旋转数组的情况——左子列非递减,右子列非递减,中间最小值)是「最小值在左边子列」的情况(right应该移到mid)
# 但是因为跟left比的时候如果nums[mid]大于nums[left],直接判断「最小值在右子列」(旋转数组:最小值在右子列,在mid的右边),与实际情况(非递减数组:最小值在最左边,在mid的左边)不符
# 所以每次遇到 nums[mid]>nums[left] 的情况,需要提前判断是否整体有序。
# 而且最后剩余两个元素的情况下,如果left处数小于right处,mid为left,与left相等这时候按理应该left++(错失最小值),所以遇到nums[mid]==nums[left]的情况也要分别处理。
# 如果跟右边界right比较,上述情况均不存在
# 分别考虑:nums[mid]>nums[right],mid一定位于左子列;
# nums[mid]<nums[right],mid一定位于右子列;
# nums[mid]==nums[right],即使只剩两个数,因为mid是left,所以还是两个数比较大小。很简单纯粹的三种情况。
n = len(nums)
l, r = 0, n-1
while l <= r:
mid = l + (r-l) // 2
# 整体有序(需要提前判断)
if nums[l] < nums[r]:
return nums[l]
# 左边有序
if nums[mid] > nums[l]:
l = mid + 1
# 右边有序 不能排除 mid
elif nums[mid] < nums[l]:
r = mid
# 如果相等,可忽略 left,有 mid 代替
else:
l += 1
return nums[l-1]
class Solution:
def findMin(self, nums: List[int]) -> int:
# 和 right 判断
n = len(nums)
l, r = 0, n-1
while l < r:
mid = l + (r - l) // 2
if nums[mid] > nums[r]:
l = mid + 1
elif nums[mid] < nums[r]:
r = mid
# 如果相等,可忽略 nums[r],有 mid 替代
else:
r -= 1
return nums[l]
162. 寻找峰值
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
n = len(nums)
l, r = 0, n-1
# while l < r:
# mid = l + (r - l) // 2
# if mid == n-1 or nums[mid] >= nums[mid+1]:
# r = mid
# else:
# l = mid + 1
while l <= r:
mid = l + (r - l) // 2
if mid == n-1 or nums[mid] >= nums[mid+1]:
r = mid - 1
else:
l = mid + 1
return l
167. 两数之和 II - 输入有序数组
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
# 二分查找 时间复杂度 O(nlogn)
n = len(numbers)
# index1, index2 = -1, -1
# def find(i, ans):
# l, r = i+1, n-1
# while l <= r:
# mid = l + (r - l) // 2
# if numbers[mid] == ans:
# return mid
# elif numbers[mid] > ans:
# r = mid - 1
# else:
# l = mid + 1
# return -1
# for index1 in range(n):
# ans = target - numbers[index1]
# index2 = find(index1, ans)
# if index2 > 0:
# return [index1+1, index2+1]
# 双指针
i, j = 0, n-1
while i < j:
if numbers[i] + numbers[j] == target:
return [i+1, j+1]
elif numbers[i] + numbers[j] > target:
j -= 1
else:
i+= 1
209. 长度最小的子数组
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
# # 滑动窗口 O(n)
# # 判断滑动窗口sum 是否大于 target,如果大于 target,说明满足条件,更新 res,同时缩小窗口继续判断
# # 如果小于 target,右侧扩展窗口继续判断
# n = len(nums)
# i, j = 0, 0
# total = 0
# res = n+1
# while j < n:
# total += nums[j]
# # 窗口满足条件,更新 res,缩窄左侧继续判断
# while total >= target:
# res = min(res, j-i+1)
# total -= nums[i]
# i += 1
# # 不满足条件
# j += 1
# return res if res != n+1 else 0
# 二分查找
# 利用前缀和递增,对每个下标 i,二分查找 找到最小的 j 满足 sum[j]-sum[i-1] >= target
n = len(nums)
sums = [0 for _ in range(n)]
sums[0] = nums[0]
for i in range(1, n):
sums[i] = sums[i-1] + nums[i]
# 对前缀和二分查找,找到最小的 j 满足 sum[j]-sum[i-1] >= target
def find(i):
l, r = i, n-1
while l <= r:
mid = l + (r-l) // 2
if sums[mid] - (sums[i-1] if i > 0 else 0) >= target:
r = mid - 1
else:
l = mid + 1
return l
res = n+1
for i in range(n):
j = find(i)
print(i, j)
if j < n:
res = min(res, j-i+1)
return res if res != n+1 else 0
240. 搜索二维矩阵 II
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
# # 二分查找
# # 遍历每一行,对每一行单独进行二分查找 O(nlogn)
# m = len(matrix)
# n = len(matrix[0])
# def exist(target, mat):
# l, r = 0, len(mat)-1
# while l <= r:
# mid = l + (r-l) // 2
# if mat[mid] == target:
# return True
# elif mat[mid] > target:
# r = mid -1
# else:
# l = mid + 1
# return False
# for i in range(m):
# mat = matrix[i]
# if exist(target, mat):
# return True
# return False
# Z 字形查找,从矩阵右上角开始查找,如果大于 target,j--,否则 i++
# O(m+n)
m, n = len(matrix), len(matrix[0])
i, j = 0, n-1
while i < m and j >= 0:
if matrix[i][j] == target:
return True
elif matrix[i][j] > target:
j -= 1
else:
i += 1
return False
275. H 指数 II