题目分析
题目给出了一个电商“双十一”购物的优惠计算问题,要求计算小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],因此享受 的优惠。
- 对于 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],因此享受 的优惠。
所以,总优惠为 。
示例 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],因此享受 的优惠。
- 对于 p[3]=3p[3]=3,前面有一个商品 p[2]=2p[2]=2,满足 p[3]≥p[2]p[3]≥p[2],因此享受 的优惠。
- 对于 p[4]=5p[4]=5,前面有一个商品 p[3]=3p[3]=3,满足 p[4]≥p[3]p[4]≥p[3],因此享受 的优惠。
所以,总优惠为 。
示例 3:
输入:
Copy Code
N = 4
p = [4, 3, 2, 1]
解释:
- 对于每个商品,由于后面没有比当前商品小的商品,无法享受任何优惠。
- 所以,总优惠为 。
解题思路
该问题的核心在于对于每个商品 p[i]p[i],找到之前离它最近的、价格不大于它的商品 p[j]p[j](j<ij<i)。如果找到了这样一个商品 p[j]p[j],则小F可以享受商品 p[j]p[j] 的价格作为优惠。
思路分析
-
暴力解法:
- 对于每个商品 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 可能效率较低。
-
优化解法(单调栈) :
- 我们可以使用栈来优化这个过程。栈的作用是存储价格较小的商品,帮助我们快速找到离当前商品最近的价格较小或等于的商品。
- 使用栈时,我们从左到右遍历商品价格,对于每个商品 p[i]p[i],我们可以通过栈找到距离它最近的符合条件的商品 p[j]p[j]。栈中的元素保持递减,因此我们只需要检查栈顶元素即可。
单调栈解法
-
初始化一个空栈,用来存储商品价格的索引。
-
遍历价格数组,对于每个商品 p[i]p[i]:
- 如果栈不为空且栈顶元素对应的商品价格大于等于当前商品价格 p[i]p[i],那么当前商品 p[i]p[i] 可以享受栈顶商品的价格作为优惠。
- 将当前商品的价格索引压入栈中。
-
计算每个商品的优惠,并累加得到总优惠。
代码实现
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),大大提高了计算效率。这个问题不仅考察了对优惠计算的理解,还考察了单调栈的应用技巧。