200字
流量波峰
2025-11-30
2025-12-14

题目描述

一线运维人员在对通话流量进行监控,每一段时间内都是出现流量的高峰,流量有高有低形成一个个波峰波谷,运维人员想找到流量变化最快的波峰,你可以帮助他吗? 给定一个整数数组nums,代表采样点的流量值,

请找到满足以下条件的三元组(i,j,k):其中i<j<k,nums[j] > nums[i]且nums[j] > nums[k] (即j是峰顶),并找到所有满足条件的三元组中(k-i)的最小值 输入描述 第一行为n个整数,表示数组中的n个元素,0<= n < =100000 输出描述 返回所有满足条件的三元组中(k-i)的最小值。若不存在,返回-1。

题目整理

我们有一个数组 nums,要找三元组 (i, j, k) 满足:

  1. i < j < k

  2. nums[j] > nums[i]nums[j] > nums[k]

  3. 也就是说 j 是一个峰顶,nums[i]nums[k] 分别在 j 的左右,并且都比 nums[j] 小。

目标:在所有这样的三元组中,找到 最小的 k - i 值。
如果不存在这样的三元组,返回 -1

关键点

  • j 必须严格大于左右两边的值。

  • 我们只关心 k - i 最小,也就是左右两个谷 ik 离得最近。

  • 注意 ik 不一定紧挨着 j,可以隔开一些元素,只要 i < j < k 并且 nums[i] < nums[j]nums[k] < nums[j] 即可。

我们要找的是所有“山峰” j 的左右最近的小于它的 i 和 kk-i 的最小值。
“最近”是指在所有满足条件的 ik 中,k-i 最小,并不是指 ikj 最近,而是它们之间的距离最小。

问题分析

我们需要找到所有山峰 j,然后为每个 j 找到:

  • 左边最近的比 nums[j] 小的数 nums[i]

  • 右边最近的比 nums[j] 小的数 nums[k]

然后计算 k-i 的最小值。

def find_small(nums, local):
    # 根据方向参数local,统一处理左右较小值查找
    # 返回每个位置在指定方向的第一个较小值索引
    stack = []
    result = [-1] * len(nums)
    if local == 'left':
        for i in range(len(nums)):
            while stack and nums[stack[-1]] >= nums[i]:
                stack.pop()
            if stack:
                result[i] = stack[-1]
            stack.append(i)
    else:
        for i in range(len(nums) - 1, -1, -1):
            while stack and nums[stack[-1]] >= nums[i]:
                stack.pop()
            if stack:
                result[i] = stack[-1]
            stack.append(i)

    return result


def find_all_valid_j(nums):
    # 获取左右较小值数组
    # 遍历所有可能的位置j(1到n-2)
    # 检查j是否满足:左右都有较小值
    # 返回所有有效山峰位置
    valid_j = []
    left_smaller = find_small(nums, 'left')
    right_smaller = find_small(nums, 'right')
    for j in range(1, len(nums) - 1):
        if left_smaller[j] != -1 and right_smaller[j] != -1:
            valid_j.append(j)
    return valid_j, left_smaller, right_smaller


def cal_min_distance(nums):
    # 获取所有有效山峰
    # 遍历每个有效山峰,计算k-i距离
    # 返回最小距离,无解返回-1
    valid_j, left_smaller, right_smaller = find_all_valid_j(nums)
    min_distance = float('inf') # min_distance = float('inf') 是初始化最小值为正无穷大。float('-inf') 表示负无穷大
    if not valid_j:
        return -1
    for j in valid_j:
        i = left_smaller[j]
        k = right_smaller[j]
        distance = k - i
        min_distance = min(min_distance, distance)

    return min_distance

def main():
    nums = list(map(int,input().split()))
    print(cal_min_distance(nums))

if __name__ == '__main__':
    main()

算法步骤逻辑总结:

  1. 预处理左较小值:使用单调栈从左到右扫描,记录每个元素左边第一个小于它的索引

  2. 预处理右较小值:使用单调栈从右到左扫描,记录每个元素右边第一个小于它的索引

  3. 识别有效山峰:遍历所有位置,筛选出左右都有较小值的峰顶位置j

  4. 计算最小距离:对每个有效山峰,计算其左右较小值索引的距离k-i,取所有距离中的最小值

  5. 处理边界情况:若无有效山峰则返回-1

通过单调栈分别找到每个元素左右第一个较小值的索引,然后遍历所有满足山峰条件的位置,计算其左右较小值索引的距离并取最小值。

输入数组 → 单调栈找left_smaller → 单调栈找right_smaller → 识别有效山峰 → 计算最小距离 → 输出结果
    ↓           ↓               ↓             ↓             ↓           ↓
  [3,5,4,7,2,1] → [-1,0,0,2,-1,-1] → [4,2,4,4,5,-1] → [1,2,3] → min(2,4,2) → 2

流量波峰
作者
Shisuiyi
发表于
2025-11-30
License
CC BY-NC-SA 4.0

评论