题目重点:明确重叠按每个square分别计面积,和几何并集是不同版本。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练输入axis-aligned square(x,y,side),整数y/side,side>0;切线水平,求下方总面积为一半的最小y。
- 每square面积独立相加,重叠重复计。题目只给平分面积方向线索,union/任意角度未给,应当待核变体。
解题路线
- square在[y,y+side]内,下方面积随切高线性增长,斜率side。y加side斜率,y+side减side,按事件扫描面积积分。
- 目标totalArea/2;在某段previous..current跨目标时,解previous+(target−area)/slope。用Fraction对整数输入保持精确。
- 若刚好到目标且下一段斜率0,所有该空隙高度都平分,选最小previous。union版斜率需当前x区间并集长度,不是side之和,应另用sweep/区间覆盖树。
手动走一遍
square边2在y0和边2在y4,总面积8,低块在y2面积4,最小切高2,空隙2..4全部平分。两个完全重叠square各side2,相加总8,切高1;与union总4数值目标不同,虽这个例子切点恰相同。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from fractions import Fraction
def bisect_squares(squares):
events={};total=0
for x,y,side in squares:
if type(side) is not int or side<=0 or type(y) is not int:raise ValueError("integer y and positive integer side required")
events[y]=events.get(y,0)+side;events[y+side]=events.get(y+side,0)-side;total+=side*side
if not total:return None
target=Fraction(total,2);area=Fraction(0);slope=0;previous=None
for y in sorted(events):
if previous is not None:
added=slope*(y-previous)
if area==target:return Fraction(previous)
if slope and area+added>=target:return previous+(target-area)/slope
area+=added
slope+=events[y];previous=y
raise AssertionError("unreachable")
复杂度
n square排序O(nlogn)、扫描O(n)、空间O(n),精确有理数算术位成本另计。union需更复杂的x覆盖结构。
易错点与追问
容易失分的边界
- 用n个square中心平均值一般不能平分面积,大小权重不同。
- 二分可行但要给误差合同,不能将近似小数称精确答案。
继续深挖
- union面积版如何维护cover count和covered x-length?
- 切线方向未限定时,有无限解,如何确定输出要求?
