题目重点:按题目 B∈(0.5A+7,A] 的条件统计有向请求;频次配对时同龄须减去自请求。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 一笔请求是发送者 A→接收者 B 的有向 pair,同一人不能请求自己;输入年龄为非负整数。
- 只采用题目明示条件,不额外引入其他年龄限制;B 的上界包含 A,下界严格大于 0.5A+7。
解题路线
- 先给 O(n²) 人对 oracle:遍历 i≠j,满足 2B>A+14 且 B≤A 就 +1,乘 2 避免浮点。
- 建 age→count;遍历出现过的年龄 A/B。A≠B 且合法时贡献 count[A]×count[B];A=B 时贡献 count[A]×(count[A]−1)。
- 年龄值域若很小可建前缀频次,把 A 允许范围的接收者数一次查出,再减掉自己;是否值得由值域上限决定。
- 边界测 A=14/15、同龄 1 人/2 人、B 恰等于半数+7 和 B>A。
手动走一遍
年龄 [16,16,17]:16→16 可发 2 笔;17→16 两人各一笔共 2;17→17 自己禁止,所以总 4。对 16,0.5×16+7=15,接收者 16 合法。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from collections import Counter
def count_friend_requests(ages):
"""Directed requests: B > A/2+7 and B <= A; no self requests."""
frequencies = Counter(ages)
total = 0
for age_a, count_a in frequencies.items():
for age_b, count_b in frequencies.items():
if 2 * age_b <= age_a + 14 or age_b > age_a:
continue
total += count_a * (count_b - 1 if age_a == age_b else count_b)
return total
复杂度
U 种不同年龄时频次解 O(n+U²) 期望时间、O(U) 空间;若已知年龄值域很小可用前缀和降至 O(n+V)。
易错点与追问
容易失分的边界
- 把有向 pair 当无向组合。
- 同龄频次平方却忘减自身。
- 把严格下界写成 ≥。
- 未经题目授权加入额外业务年龄规则。
继续深挖
- 年龄值域有限怎样 O(n+V)?
- 年龄数据流动态更新怎样维护总数?
- 若要列出请求 pair 而非计数?
