binary search 定义
想要使用“二分搜索”,这“一堆数”必须有以下特征:
- 存在数组中
- 有序排列(无序的话,二分法用来当猜答案的方法)
模版
二分法的传统应用
PS:模版二、三最好
278. 第一个错误的版本(Easy)
Solu:
运用「模版三」:mid = left是最后一个good version;right = left + 1是第一个bad version
Code:
class Solution:
def firstBadVersion(self, n):
"""
:type n: int
:rtype: int
"""
l, r = 1, n
while l <= r:
mid = (l + r) // 2
if isBadVersion(mid):
r = mid - 1
else:
l = mid + 1
return l
4. 寻找两个正序数组的中位数(Hard)
Solu:
mid1=nums1分割后右半部分的起始index- 一分为二,只和切口处的4个elements有关
- 因为
#分割线左半边元素的总数 = (len(nums1)+len(nums2)) // 2是固定的,所以可以顺势计算出nums2的分割点mid2
- 一旦满足
分割线左半部分的所有元素 < 分割线右半部分的所有元素,则找到了“中位数”- 此时根据总长度的奇偶性判断median具体怎么算
Code:
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
if len(nums1) > len(nums2):
nums1, nums2 = nums2, nums1
l, r, total = 0, len(nums1), len(nums1) + len(nums2)
while l <= r:
m1 = (l + r) // 2
m2 = (total + 1) // 2 - m1
left1 = -float('inf') if m1 == 0 else nums1[m1 - 1]
right1 = float('inf') if m1 == len(nums1) else nums1[m1]
left2 = -float('inf') if m2 == 0 else nums2[m2 - 1]
right2 = float('inf') if m2 == len(nums2) else nums2[m2]
if max(left1, left2) <= min(right1, right2):
if total % 2 == 0: # even length
return float((max(left1, left2) + min(right1, right2)) / 2)
else: # odd length
return float(max(left1, left2))
elif right1 < left2: # nums1's left partition is too small
l = m1 + 1
else: # nums2's left partition is too small
r = m1 - 1
return -1
二分法去猜最终答案
❤️ 410. 分割数组的最大值
Solu:
max(nums) ≤ 子数组的最大值 ≤ sum(nums)必定成立- 先猜一个最终结果
mid值,然后遍历数组划分,使每个子数组和都最接近mid(贪心地逼近mid),这样得到的满足sum(subArray) <= mid的子数组数一定最少;- 如果即使这样,仍旧
#子数组数量 > m - 1个,那么明显说明mid猜小了,因此lo = mid + 1; - 而如果得到的
#子数组数量 ≤ m - 1个,那么可以尝试更小的mid,因此hi = mid - 1;
- 如果即使这样,仍旧
当问题除了暴力解没有其他思路的时候,用二分法去“猜”答案也是一种解法
Code:
class Solution:
def splitArray(self, nums: List[int], m: int) -> int:
def valid(subArraySum):
curSum, count = 0, 0
for num in nums:
curSum += num
if curSum > subArraySum:
count += 1
curSum = num
if count >= m:
return False
return True
def binary(low, high):
while low <= high:
mid = (low + high) // 2
if valid(mid): # 尽量往小的答案猜
high = mid - 1
else:
low = mid + 1
return low
return binary(max(nums), sum(nums))
同思路类似题目还有:
- 1552. Magnetic Force Between Two Balls
-
- Minimum Number of Days to Make m Bouquets
-
- Find the Smallest Divisor Given a Threshold
-
- Maximum Side Length of a Square with Sum Less than or Equal to Threshold
Reference: