SWE · Coding

每位置后面更小的数量:逆序Fenwick计频

只统计严格小于,重复值不会互计。

题目重点:只统计严格小于,重复值不会互计。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 整数数组,输出与原位置对应的数量;标题相似线索采用标准严格小于训练合同。
  • 若正式变体是≤或距离范围,要修改查询边界或过期状态。

解题路线

  1. 压缩排序不同值,逆序时树内恰存当前右侧所有元素。query(rank−1)给更小频次,随后插当前rank。
  2. 0基压缩rank对应Fenwick插入rank+1;查询i=rank恰覆盖0..rank−1,这是最常见的边界风险。
  3. 返回逆序累积结果再反转。排序压缩O(nlogn),不是原数组本身排序后返回,位置顺序必须保留。

手动走一遍

[5,2,6,1]输出[2,1,1,0]。[2,2,1]前两个2各只计右侧1,不计另一2,结果[1,1,0]。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from bisect import bisect_left


def count_smaller(a):
    values=sorted(set(a));tree=[0]*(len(values)+1);answer=[]
    for x in reversed(a):
        rank=bisect_left(values,x);i=rank;count=0
        while i:count+=tree[i];i-=i&-i
        answer.append(count);i=rank+1
        while i<len(tree):tree[i]+=1;i+=i&-i
    return answer[::-1]

复杂度

O(nlogn)时间、O(n+d)空间;Fenwick单更新/查询O(logd),d不同值。

易错点与追问

容易失分的边界

  • 当前值先入树再查询≤时可能计自己;本文查严格小可免自计但仍保持清晰先查后加。
  • 统计全局更小值会包括左边元素。

继续深挖

  • 只看后W个位置如何加右侧过期删除?
  • merge-sort计逆序贡献怎样避免数据移动后丢原index?
✓已复制微信号!