本文介绍如何找出列表中所有满足“严格大于其之前所有元素”的位置索引(即“当前最大值”索引),提供简洁的循环实现、numpy向量化方案,并对比性能与适用场景。
本文介绍如何找出列表中所有满足“严格大于其之前所有元素”的位置索引(即“当前最大值”索引),提供简洁的循环实现、numpy向量化方案,并对比性能与适用场景。
在数据分析和算法处理中,常需识别序列中首次出现的新高点——即某个元素比它前面所有元素都大,这类索引被称为“当前最大值索引”(running strict maxima indices)或“记录点”(record highs)。例如,对列表 a = [3, 1, 4, 1, 5, 9, 2, 6],满足 a[i] > max(a[0:i]) 的索引为 [0, 2, 4, 5](对应值 3, 4, 5, 9),因为它们依次打破了历史最高纪录。
✅ 推荐实现:单次遍历(O(n) 时间,O(1) 额外空间)
最直观且高效的方式是线性扫描,仅维护当前遇到的最大值和结果索引列表:
该方法时间复杂度为 O(n),空间复杂度为 O(k)(k 为峰值个数),无依赖、可读性强,适用于任意可比较类型的序列(如 int, float, str)。
? 进阶方案:NumPy 向量化(适合大型数值数组)
若处理的是大型数值列表(如百万级浮点数组),可借助 NumPy 实现更简洁的向量化写法(利用 np.maximum.accumulate):
⚠️ 注意:np.maximum.accumulate(a) 给出的是
累积最大值数组
,但直接 a == cummax 在存在重复最大值(如 [2, 2, 1])时会错误包含第二个 2。因此我们采用 arr[1:] > cummax[:-1] 确保“严格大于前序所有值”,并显式保留首项。
? 对比与选型建议
方案优点缺点适用场景原生 Python 循环零依赖、逻辑清晰、内存友好、支持任意类型无显著缺点通用首选,尤其小至中等规模数据或非数值类型NumPy 向量化大数组下速度更快(C 层优化)、代码紧凑需引入 NumPy、不支持不可哈希/不可比较类型(如自定义对象)、内存占用略高数值密集型任务,数组长度 ≥ 10⁴ 且已使用 NumPy 生态
? 小结
Python 标准库中
没有内置函数
直接实现该逻辑(如 itertools 或 functools 中均无对应工具),这源于其使用场景相对特定,且单次遍历已足够高效。因此,推荐优先使用简洁的原生循环实现;若已在 NumPy 环境中处理大规模数值数据,可选用向量化版本以提升性能。无论哪种方式,核心思想始终一致:
一次扫描,动态更新历史最大值,即时记录突破点索引
。
def find_running_max_indices(a):
if not a:
return []
indices = [0] # 第一个元素总是“当前最大值”
max_so_far = a[0]
for i in range(1, len(a)):
if a[i] > max_so_far:
indices.append(i)
max_so_far = a[i]
return indices
# 示例
a = [3, 1, 4, 1, 5, 9, 2, 6]
print(find_running_max_indices(a)) # 输出: [0, 2, 4, 5]import numpy as np
def find_running_max_indices_numpy(a):
arr = np.asarray(a)
if arr.size == 0:
return []
cummax = np.maximum.accumulate(arr)
# 当前值等于累积最大值 且 严格大于左侧累积最大值(处理重复时确保“严格大于”)
# 注意:cummax[i] == arr[i] 表示它是到 i 为止的新最大值;但需排除相等但非严格超越的情况
# 更稳妥做法:比较 arr[i] > cummax[i-1](i>0),首项单独处理
mask = np.concatenate(([True], arr[1:] > cummax[:-1]))
return np.where(mask)[0].tolist()
# 示例验证
a = [3, 1, 4, 1, 5, 9, 2, 6]
print(find_running_max_indices_numpy(a)) # [0, 2, 4, 5]