优惠计算问题

227 阅读4分钟

题目分析

题目给出了一个电商“双十一”购物的优惠计算问题,要求计算小F在购买多个商品时能够获得的总优惠。

问题描述

小F在“双十一”期间购买了 NN 件商品,每件商品的价格为 p[i]p[i]。对于每个商品 p[i]p[i],如果该商品的价格大于等于之前某个商品 p[j]p[j](且 j<ij<i),小F可以获得该商品 p[j]p[j] 的价格作为优惠,前提是 p[j]p[j] 是离 p[i]p[i] 最近的且满足条件的商品。

举个例子

示例 1:

输入:

Copy Code
N = 5
p = [9, 4, 5, 2, 4]

解释:

  • 对于 p[1]=9p[1]=9,没有前面的商品,所以没有优惠。
  • 对于 p[2]=4p[2]=4,没有比 p[2]p[2] 更小或等于的商品,所以没有优惠。
  • 对于 p[3]=5p[3]=5,前面有一个商品 p[1]=4p[1]=4,满足 p[3]≥p[1]p[3]≥p[1],因此享受 44 的优惠。
  • 对于 p[4]=2p[4]=2,没有比 p[4]p[4] 更小或等于的商品,所以没有优惠。
  • 对于 p[5]=4p[5]=4,前面有一个商品 p[2]=4p[2]=4,满足 p[5]≥p[2]p[5]≥p[2],因此享受 44 的优惠。

所以,总优惠为 4+4=84 + 4 = 8

示例 2:

输入:

Copy Code
N = 4
p = [1, 2, 3, 5]

解释:

  • 对于 p[1]=1p[1]=1,没有前面的商品,所以没有优惠。
  • 对于 p[2]=2p[2]=2,前面有一个商品 p[1]=1p[1]=1,满足 p[2]≥p[1]p[2]≥p[1],因此享受 11 的优惠。
  • 对于 p[3]=3p[3]=3,前面有一个商品 p[2]=2p[2]=2,满足 p[3]≥p[2]p[3]≥p[2],因此享受 22 的优惠。
  • 对于 p[4]=5p[4]=5,前面有一个商品 p[3]=3p[3]=3,满足 p[4]≥p[3]p[4]≥p[3],因此享受 33 的优惠。

所以,总优惠为 1+2+3=61 + 2 + 3 = 6

示例 3:

输入:

Copy Code
N = 4
p = [4, 3, 2, 1]

解释:

  • 对于每个商品,由于后面没有比当前商品小的商品,无法享受任何优惠。
  • 所以,总优惠为 00

解题思路

该问题的核心在于对于每个商品 p[i]p[i],找到之前离它最近的、价格不大于它的商品 p[j]p[j](j<ij<i)。如果找到了这样一个商品 p[j]p[j],则小F可以享受商品 p[j]p[j] 的价格作为优惠。

思路分析

  1. 暴力解法

    • 对于每个商品 p[i]p[i],我们可以遍历它前面所有的商品 p[j]p[j](j<ij<i),找到第一个满足 p[i]≥p[j]p[i]≥p[j] 的商品 p[j]p[j],并将其作为优惠。
    • 时间复杂度为 O(N2)O(N2),对于较大的 NN 可能效率较低。
  2. 优化解法(单调栈)

    • 我们可以使用栈来优化这个过程。栈的作用是存储价格较小的商品,帮助我们快速找到离当前商品最近的价格较小或等于的商品。
    • 使用栈时,我们从左到右遍历商品价格,对于每个商品 p[i]p[i],我们可以通过栈找到距离它最近的符合条件的商品 p[j]p[j]。栈中的元素保持递减,因此我们只需要检查栈顶元素即可。

单调栈解法

  1. 初始化一个空栈,用来存储商品价格的索引。

  2. 遍历价格数组,对于每个商品 p[i]p[i]:

    • 如果栈不为空且栈顶元素对应的商品价格大于等于当前商品价格 p[i]p[i],那么当前商品 p[i]p[i] 可以享受栈顶商品的价格作为优惠。
    • 将当前商品的价格索引压入栈中。
  3. 计算每个商品的优惠,并累加得到总优惠。

代码实现

pythonCopy Code
def calculate_discount(N, p):
    # 初始化栈和总优惠
    stack = []
    total_discount = 0
    
    for i in range(N):
        # 如果栈不为空且当前价格 >= 栈顶商品的价格
        while stack and p[stack[-1]] > p[i]:
            stack.pop()  # 弹出栈顶元素
        if stack:
            total_discount += p[stack[-1]]  # 获得优惠
        # 将当前商品的索引入栈
        stack.append(i)
    
    return total_discount

# 示例
N1, p1 = 5, [9, 4, 5, 2, 4]
N2, p2 = 4, [1, 2, 3, 5]
N3, p3 = 4, [4, 3, 2, 1]

print(calculate_discount(N1, p1))  # 输出: 6
print(calculate_discount(N2, p2))  # 输出: 6
print(calculate_discount(N3, p3))  # 输出: 0

复杂度分析

  • 时间复杂度:每个商品价格最多会被入栈和出栈一次,因此时间复杂度为 O(N)O(N)。
  • 空间复杂度:栈中最多存储 NN 个商品的索引,因此空间复杂度为 O(N)O(N)。

总结

通过使用栈来优化计算过程,我们将暴力解法的时间复杂度从 O(N2)O(N2) 降低到 O(N)O(N),大大提高了计算效率。这个问题不仅考察了对优惠计算的理解,还考察了单调栈的应用技巧。