题目重点:按明确的年龄阈值计算有向好友请求数量,保留与常见标准题不同的等号和百岁限制。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 每个人向另一个人最多发一个请求;收件年龄b必须满足b>=a/2+7、b<=a;若发件a>100,收件b<100禁止。相同年龄的人仍是不同个体。
- 同题标准版要求b>a/2+7且b<=a,另排除b>100而a<100(该项已被b<=a蕴含)。标准版没有“a>100不发b<100”的反向排除。两份谓词分别实现,练习前确认版本。
解题路线
- 按年龄排序。每个发件a的合法收件区间下界为ceil((a+14)/2),若a>100再与100取max;上界a。二分算该闭区间内人数。
- 若区间为空则零;若非空且a自己在区间内,减去1排除本人。相同年龄其他个体仍保留,无需去重年龄列表。
- 把分数不等式变2b>=a+14,整数下界为(a+15)//2,避免浮点舍入。每个发件独立累加,所以双方互发算两次。
- 标准版整数下界为floor(a/2+7)+1,即a//2+8,不再max(lower,100)。用count_standard_requests验证标准版,包含阈值与反向百岁排除仍在count_custom_requests。
手动走一遍
[110,130,90]中130可向110发送;110不能向90发(a>100/b<100),90不能发给更年长者,答案1。年龄14向另一个14可以发,因为14>=14,等号不能改成严格大于。 对[14,14],变体互发2次,标准版0;[101,99],标准版101可向99发一次,变体禁止,这两例能明确分开条件。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def count_custom_requests(ages):
"""Recipient >= sender/2+7, <=sender; sender>100 forbids recipient<100.
This is the declared custom contract, not standard LC825.
Individuals are distinct even when their ages are equal. Exclude self.
"""
from bisect import bisect_left, bisect_right
if any(not isinstance(a, int) or a <= 0 for a in ages):
raise ValueError("positive integer ages required")
ordered = sorted(ages)
answer = 0
for age in ordered:
# 2*recipient >= age+14: integer ceiling avoids floating rounding.
lower = (age + 15) // 2
if age > 100:
lower = max(lower, 100)
if lower > age:
continue
answer += bisect_right(ordered, age) - bisect_left(ordered, lower) - 1
return answer
def count_standard_requests(ages):
"""Standard: recipient > sender/2+7 and recipient<=sender.
The additional 'recipient>100 and sender<100' exclusion is already implied
by recipient<=sender, unlike the reversed-age exclusion in custom contract.
"""
from bisect import bisect_left, bisect_right
if any(not isinstance(a,int) or a<=0 for a in ages):raise ValueError('positive integer ages')
ordered=sorted(ages);answer=0
for age in ordered:
lower=age//2+8
if lower<=age:answer+=bisect_right(ordered,age)-bisect_left(ordered,lower)-1
return answer
复杂度
O(n log n)排序与二分时间,O(n)排序副本空间;若年龄范围有限,可频率与前缀人数把查询降为常数。
易错点与追问
容易失分的边界
- 照搬标准825的谓词会在等号和百岁方向上给不同答案。
- 年龄列表去重会丢掉同龄人的组合数,减本人也不能减掉整个同龄组。
继续深挖
- 频次版对于age=a每人能向count(a)−1同龄人发,总贡献count(a)(count(a)−1)。
- 如何同时验证标准版与变体?分别写清谓词,用所有有向(i,j)暴力枚举核对,不能共用一个未声明条件。
