题目重点:交易与规则逐行对齐,按金额乘法、累计客户频次和同小时频次顺序更新每个商户的整数分数。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 每笔 transaction 与同下标 rule 一一对应;transaction=(merchant,amount,customer,hour),rule=(minimum_amount,multiplier,repeat_addition,hourly_adjustment)。
- 只接受初始商户表中已有的 merchant,按表中顺序输出;CSV 简化成无引号的四段/两段格式。正式题如支持字段内逗号须换 parser。
- 高额条件严格 amount>minimum_amount;同商户客户第 4 笔起加分;同商户客户同小时第 3 笔起作时段奖惩。当前笔先计入次数再应用三规则。
解题路线
- 解析并检查交易/规则行数、商户 ID 唯一、小时 0..23;把每个商户分数保存在 map,输出顺序另用列表保持。
- 按输入顺序处理。对 (merchant,customer) 与 (merchant,customer,hour) 分别递增计数,绝不能把两个客户或不同商户的频次混在一起。
- 取商户当前分数,若 amount>limit 先乘 factor;若 pair count>3 再加 addition;若 hourly count≥3,12..17 加 adjustment,9..11 或 18..22 减 adjustment,其他小时不动;保存新分数。
- 用扫描既有历史的慢参考实现独立对照计数 map,覆盖第 2/3/4 笔、时段边界、金额恰等阈值、规则顺序和负分数。
手动走一遍
训练例初始 m=10,同一客户同一商户同一 12 点四笔金额均不超阈值、每笔 addition=2、adjustment=3:前两笔保持 10;第 3 笔小时规则加 3 得 13;第 4 笔客户总频次加 2 且小时规则加 3 得 18。若第 4 笔也触发乘 2,应先将 13 乘 2 再加 2+3,结果 31。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from __future__ import annotations
def score_merchants(
transactions: list[str], rules: list[str], merchants: list[str]
) -> list[str]:
"""Training contract from the reported OA; amounts/scores are integers.
Transaction: merchant,amount,customer,hour
Rule: minimum_amount,multiplier,repeat_addition,hourly_adjustment
Merchant: id,initial_score
"""
if len(transactions) != len(rules):
raise ValueError("each transaction requires its own rule")
scores: dict[str, int] = {}
order: list[str] = []
for line in merchants:
name, raw_score = (field.strip() for field in line.split(","))
if not name or name in scores:
raise ValueError("merchant IDs must be nonempty and unique")
scores[name] = int(raw_score)
order.append(name)
pair_counts: dict[tuple[str, str], int] = {}
hourly_counts: dict[tuple[str, str, int], int] = {}
for transaction, rule in zip(transactions, rules):
merchant, raw_amount, customer, raw_hour = (
field.strip() for field in transaction.split(",")
)
raw_limit, raw_factor, raw_add, raw_adjust = (
field.strip() for field in rule.split(",")
)
amount, hour = int(raw_amount), int(raw_hour)
limit, factor, addition, adjustment = map(
int, (raw_limit, raw_factor, raw_add, raw_adjust)
)
if merchant not in scores or not customer or not 0 <= hour <= 23:
raise ValueError("unknown merchant, empty customer or invalid hour")
pair = (merchant, customer)
hourly = (merchant, customer, hour)
pair_counts[pair] = pair_counts.get(pair, 0) + 1
hourly_counts[hourly] = hourly_counts.get(hourly, 0) + 1
score = scores[merchant]
if amount > limit:
score *= factor
if pair_counts[pair] > 3:
score += addition
if hourly_counts[hourly] >= 3:
if 12 <= hour <= 17:
score += adjustment
elif 9 <= hour <= 11 or 18 <= hour <= 22:
score -= adjustment
scores[merchant] = score
return [f"{merchant},{scores[merchant]}" for merchant in order]
复杂度
T 笔交易、M 个商户时,哈希 map 期望 O(T+M) 时间、O(T+M) 最坏不同 pair/hour 键空间;朴素历史重扫为 O(T²),仅用于小样本独立验证。超大整数乘法需考虑语言的溢出或业务上限。
易错点与追问
容易失分的边界
- 把规则列表当通用规则集而不是逐笔对齐。
- 用 >3 判断小时频次,错过第 3 笔;用 ≥3 判断总频次,提前一笔加分。
- 先加分再乘使结果不同。
- hour 9/11/12/17/18/22 的包含边界写错,或不稳定输出商户顺序。
- 把作者的 AI 整理稿视作官方精确签名,忽视是否存在引号和负数约束缺口。
继续深挖
- 交易同一小时但日期不同是否仍算同一桶?题目只有 hour 字段,不能自行推断跨天。
- 规则若按商户动态更新而非逐笔一一对应,数据模型怎样改?
- 若要并行处理同商户交易,怎样保持原始顺序与最终分数一致?
