Leetcode 二分法
标签: Leetcode 二分法 Python博客 51CTO博客
2023-05-15 18:24:06 226浏览
二分法
- 475. 供暖器
- 方法一:二分查找
- 方法二:滑动窗口
- [374. 猜数字大小](https://leetcode-cn.com/problems/guess-number-higher-or-lower/)
- [35. 搜索插入位置](https://leetcode-cn.com/problems/search-insert-position/)
- 方法一:
- 方法二:二分
- [69. Sqrt(x)](https://leetcode-cn.com/problems/sqrtx/)
- 方法一:袖珍计算器算法
- 方法二:二分查找
- 方法三:牛顿迭代
- 方法四:位运算
- [240. 搜索二维矩阵 II](https://leetcode-cn.com/problems/search-a-2d-matrix-ii/)
- 方法一:直接查找
- 方法二:二分查找
- 方法三:Z 字形查找
- [852. 山脉数组的峰顶索引](https://leetcode-cn.com/problems/peak-index-in-a-mountain-array/)
- [278. 第一个错误的版本](https://leetcode-cn.com/problems/first-bad-version/)
- [367. 有效的完全平方数](https://leetcode-cn.com/problems/valid-perfect-square/)
475. 供暖器
Leetcode 在加热站中找到每个房屋需要的最小半径的最大值
方法一:二分查找
class Solution:
def findRadius(self, houses: List[int], heaters: List[int]) -> int:
heaters.sort()
# heaters.insert(0, -inf) # 添加哨兵
# heaters.append(inf)
# res = 0
# for h in houses:
# # 二分法找 h 右边最近加热器, 减一为左边
# idx = bisect.bisect(heaters, h)
# res = max(res, min(h - heaters[idx - 1], heaters[idx] - h))
res, n = 0, len(heaters)
for h in houses:
left, right = 0, n;
while left < right:
mid = left + (right - left) // 2
if h > heaters[mid]: left = mid + 1
else: right = mid
dist1 = inf if right == 0 else h - heaters[right - 1]
dist2 = inf if right == n else heaters[right] - h
res = max(res, min(dist1, dist2))
return res
方法二:滑动窗口
class Solution:
def findRadius(self, houses: List[int], heaters: List[int]) -> int:
houses.sort()
heaters.sort()
heaters.insert(0, -inf) # 添加哨兵
heaters.append(inf)
i, ans = 0, 0
for h in houses:
while heaters[i] <= h: # 找 h 右边第一个热站(刚好 > h), i - 1 是左边的第一个或正好是 h
i += 1
ans = max(ans, min(h - heaters[i-1], heaters[i] - h))
# h 后面的不可能使用,i - 1 前面的热站,所以从 i 继续循环。 [heaters[i-1], heaters[i]] 滑动窗口
return ans
374. 猜数字大小
class Solution:
def guessNumber(self, n: int) -> int:
left, right = 1, n
while left < right:
mid = (left + right) // 2
if guess(mid) <= 0:
right = mid # 答案在区间 [left, mid] 中
else:
left = mid + 1 # 答案在区间 [mid+1, right] 中
# 此时有 left == right,区间缩为一个点,即为答案
return left
35. 搜索插入位置
方法一:
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
n = len(nums)
if target > nums[-1]: return n # 最后
if target < nums[0]: return 0 # 开头
for i in range(n):
if nums[i] == target: return i # 相等
if nums[i] > target: return i # 刚好大于位置
方法二:二分
在数组中插入目标值,四种情况:

在二分查找的过程中,保持不变量——循环不变量。
闭区间
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
n = len(nums)
l, r = 0, n - 1 # 定义 target 在闭区间 [left, right]
while l <= r: # 当 left == right,区间 [left, right] 依然有效
mid = (l + r) // 2
if nums[mid] == target: return mid
if nums[mid] < target: l = mid + 1 # target 在右区间 [middle+1, right]
else: r = mid - 1 # target 在左区间 [left, middle-1]
return l # or r + 1 左边 l 或右边 r + 1
#return bisect.bisect_left(nums, target)
半开半闭区间
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
n = len(nums)
l, r = 0, n # 定义 target 在半闭半开区间 [left, right)
while l < r: # 因为 left == right 的时候,[left, right)是空区间
mid = (l + r) >> 1
if nums[mid] == target: return mid
if nums[mid] < target: l = mid + 1 # target 在右区间 [middle+1, right)
else: r = mid # target 在左区间 [left, middle) 注意没有 - 1
return r # or l
69. Sqrt(x)
方法一:袖珍计算器算法
「袖珍计算器算法」是一种用指数函数 exp 和对数函数 ln 代替平方根函数的方法。
class Solution:
def mySqrt(self, x: int) -> int:
if x == 0:
return 0
ans = int(math.exp(0.5 * math.log(x)))
return ans + 1 if (ans + 1) ** 2 <= x else ans
方法二:二分查找
由于 x 平方根的整数部分 ans 是满足 ≤ x 的最大 k 值,因此可以对 k 进行二分查找,从而得到答案。
二分查找的下界为 0,上界可以粗略地设定为 x。
class Solution:
def mySqrt(self, x: int) -> int:
l, r, ans = 0, x, -1
while l <= r:
mid = (l + r) // 2
if mid * mid <= x:
ans = mid
l = mid + 1
else:
r = mid - 1
return ans
方法三:牛顿迭代
牛顿迭代法是一种可以用来快速求解函数零点的方法。

class Solution:
def mySqrt(self, x: int) -> int:
if x == 0: return 0
C, x0 = x, x
while True:
xi = 0.5 * (x0 + C / x0)
if abs(x0 - xi) < 1e-7:
break
x0 = xi
return int(x0)
方法四:位运算
class Solution:
def mySqrt(self, x: int) -> int:
res = x
while res*res > x:
res = (res + x//res) >> 1
return res
240. 搜索二维矩阵 II
方法一:直接查找
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
for row in matrix:
for element in row:
if element == target: return True
return False
方法二:二分查找
for row in matrix:
# if row[-1] < target: continue
# if row[0] > target: break
# idx = bisect.bisect_left(row, target)
# if idx < len(row) and row[idx] == target:
# return True
if target in row: return True
# return False
方法三:Z 字形查找
i, j = 0, len(matrix[0]) - 1
while i < len(matrix) and j >= 0:
if matrix[i][j] == target: return True
if matrix[i][j] > target: j -= 1
else: i += 1
# return False
852. 山脉数组的峰顶索引
```python3
class Solution:
def peakIndexInMountainArray(self, arr: List[int]) -> int:
# 方法一:
'''
for i in range(1, len(arr)-1):
if arr[i] > arr[i+1]:
return i
# 方法二:二分
i, j = 0, len(arr) - 1
while i < j:
mid = (i+j)//2
if arr[mid+1] > arr[mid]:
i = mid + 1
else:
j = mid
return j
'''
return arr.index(max(arr))
278. 第一个错误的版本
class Solution:
def firstBadVersion(self, n):
# i, j = 1, n
# while i <= j:
# mid = (i + j) // 2
# if isBadVersion(mid):
# j = mid - 1
# else:
# i = mid + 1
# return j + 1
l, r = 1, n
while l < r:
m = l + ((r - l) >> 1)
if isBadVersion(m):
r = m
else:
l = m + 1
return l
367. 有效的完全平方数
class Solution:
def isPerfectSquare(self, num: int) -> bool:
if num == 1: return True
# 方法一:二分查找
'''
i, j = 2, num // 2
while i <= j:
m = (i + j) // 2
if num == m ** 2:
return True
if num > m ** 2:
i = m + 1
else:
j = m - 1
return False
'''
# 方法二:牛顿迭代法
x = num // 2
while x * x > num:
x = (x + num // x) // 2
return x * x == num
其他「二分」相关题解
二分模板
29. 两数相除 : 二分 + 倍增乘法解法(含模板)
二分模板题
278. 第一个错误的版本 : 使用交互函数充当 check 进行二分
- 猜数字大小 : 使用交互函数充当 check 进行二分
- 山脉数组的峰顶索引 : 二分 & 三分查值问题
二分本质 & 恢复二段性处理
33. 搜索旋转排序数组(找目标值) : 严格 O(logN),一起看清二分的本质
- 搜索旋转排序数组 II(找目标值) : 详解为何元素相同会导致 O(n),一起看清二分的本质
- 寻找旋转排序数组中的最小值(找最小值) : 严格 O(logN),一起看清二分的本质
- 寻找旋转排序数组中的最小值 II(找最小值) : 详解为何元素相同会导致 O(n),一起看清二分的本质
二分 check 函数如何确定
34. 在排序数组中查找元素的第一个和最后一个位置 : 考察对「二分」的理解,以及 check 函数的「大于 小于」怎么写
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
展开评论
您可能感兴趣的博客
