Chapter 6: Sorting and Searching
# 知识解析
6.4 Binary Search
这里参照 Ruby 中 bsearch_index
的实现,take一个 function 作为参数表示需要满足的条件,找到满足条件的最小index和最大index(注意这一条件对 bsearch_low
必须是“单调递增“,对 bsearch_high
必须是“单调递减“)。
如果寻找的是具体的一个target值,需要传入 lambda ele: ele >= target
或 lambda ele: ele <= target
在找到index的上下限之后需要额外一步检查来确定是否能找到。
"""
condition should be a function that evaluates as
[False, False ... True, True, True], aka >= target
"""
def bsearch_low(arr: List[int], condition: Callable[[int], bool]) -> Optional[int]:
low = 0
high = len(arr) - 1
while low <= high:
mid = (low + high) // 2
smaller = condition(arr[mid])
if smaller:
high = mid - 1
else:
low = mid + 1
if low >= len(arr) or not condition(arr[low]):
return None
return low
"""
condition should be a function that evaluates as
[True, True ... False, False, False], aka <= target
"""
def bsearch_high(arr: List[int], condition: Callable[[int], bool]) -> Optional[int]:
low = 0
high = len(arr) - 1
while low <= high:
mid = (low + high) // 2
bigger = condition(arr[mid])
if bigger:
low = mid + 1
else:
high = mid - 1
if high < 0 or not condition(arr[high]):
return None
return high
from bsearch import bsearch_low, bsearch_high
from typing import List
def search_range(nums: List[int], target: int) -> List[int]:
lower_bound = bsearch_low(nums, lambda ele: ele >= target)
if lower_bound is None or (nums[lower_bound] != target):
return [-1, -1]
return [lower_bound, bsearch_high(nums, lambda ele: ele <= target)]
from bsearch import bsearch_low, bsearch_high
def jobScheduling(startTime: List[int], endTime: List[int], profit: List[int]) -> int:
return MaxProfitFinder(startTime, endTime, profit).max_profit()
class Job:
def __init__(self, start_time, end_time, profit):
self.start_time = start_time
self.end_time = end_time
self.profit = profit
class MaxProfitFinder:
def __init__(self, start_times, end_times, profits):
self.jobs = [
Job(start_times[idx], end_times[idx], profits[idx])
for idx in range(len(start_times))
]
self.jobs.sort(key=lambda job: job.start_time)
def find_next_job_id(self, time):
return bsearch_low(self.jobs, lambda job: job.start_time >= time)
def max_profit(self):
return self.max_profit_from_id(0)
@lru_cache(maxsize=None)
def max_profit_from_id(self, id):
if id is None or id >= len(self.jobs):
return 0
job = self.jobs[id]
next_job_id = self.find_next_job_id(job.end_time)
max_profit = max(
job.profit + self.max_profit_from_id(next_job_id),
self.max_profit_from_id(id + 1)
)
return max_profit
Last updated
Was this helpful?