个人题解|价格优惠计算问题

91 阅读4分钟

问题描述

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

例如,给定价格数组p = [9, 4, 5, 2, 4],其中p[3] = 2之前没有商品的价格小于等于p[3],因此没有优惠;而p[2] = 5可以享受最近的商品p[1] = 4的价格作为优惠。因此,任务是计算小F能获得的总优惠。

问题分析

题目要求我们为每一件商品计算其所能享受的优惠。具体来说,如果某一商品的价格 p[i]p[i] 大于等于前面某个商品的价格 p[j]p[j],则该商品可以享受 p[j]p[j] 作为优惠,而我们要计算所有商品的优惠总和。

为了高效地找到每件商品所能享受的优惠,我们可以利用单调栈来找到满足条件的最近的价格。栈中的元素会按照从大到小的顺序排列,从而保证我们能够在遍历每个商品时,快速地找到它能享受优惠的商品。

解法思路

  1. 栈的作用:我们用栈来存储商品的价格,并确保栈中的商品价格是单调递减的。当遇到一个新的商品时,我们可以通过栈来快速找到它之前满足条件的最近商品。

  2. 栈的操作

    • 当遍历到某件商品 p[i]p[i] 时,栈顶的商品 p[j]p[j] 是离 p[i]p[i] 最近且价格小于等于 p[i]p[i] 的商品。
    • 如果栈顶商品价格大于 p[i]p[i],则弹出栈顶元素,因为它不能作为 p[i]p[i] 的优惠来源。
    • 如果栈为空,说明没有找到满足条件的商品,则没有优惠。
  3. 优化:通过栈的结构,我们可以在 O(1)O(1) 时间内获取每件商品的优惠价格,从而将整个算法的时间复杂度控制在 O(N)O(N)。

代码实现

def solution(N: int, p: list) -> int:
    stack = []
    total_discount = 0
    
    for price in p:
        # 找到该商品对应的优惠商品
        while stack and stack[-1] > price:
            stack.pop()
        
        if stack:
            # 如果栈非空,栈顶商品就是最接近的符合条件的商品
            total_discount += stack[-1]
        
        # 将当前商品的价格入栈
        stack.append(price)
    
    return total_discount

if __name__ == '__main__':
    print(solution(5, [9, 4, 5, 2, 4]) == 6)
    print(solution(4, [1, 2, 3, 5]) == 6)
    print(solution(15, [2, 4, 1, 14, 13, 10, 10, 16, 6, 11, 17, 3, 1, 12, 1]) == 0)

解释

  • 栈的存储结构:栈 stack 中存储的是商品的价格,且保证栈中的商品价格单调递减。这样可以确保每次遇到新的商品时,栈顶的商品就是满足条件的最近一个商品。

  • 遍历过程

    • 对于每一个商品 price,我们会将栈中价格大于当前商品的元素弹出,因为这些商品不能作为当前商品的优惠来源。
    • 如果栈非空,栈顶元素就是满足条件的最近商品,此时将栈顶元素的价格加到总优惠上。
    • 最后将当前商品的价格入栈,准备作为后续商品的优惠来源。

复杂度分析

  • 时间复杂度:遍历一次商品数组,对于每件商品,最多会进行一次入栈和一次出栈操作,因此总的时间复杂度为 O(N)O(N),其中 NN 是商品的数量。
  • 空间复杂度:栈中最多存储 NN 个商品的价格,因此空间复杂度为 O(N)O(N)。

总结

用栈来解决这个问题的优势主要体现在以下几个方面:

  • 高效性:通过栈,可以在 O(N)O(N) 时间复杂度内解决问题,避免了暴力枚举的 O(N2)O(N2) 时间复杂度。
  • 自然的单调性:栈可以帮助我们在遍历过程中保持单调性,从而快速找到每个商品的最近优惠商品。
  • 空间时间平衡:虽然栈会使用额外的空间,但它大大提高了效率,使得算法可以处理更大规模的数据。

总的来说,栈是解决此类问题的理想数据结构,它通过局部的状态保持(栈内的元素)来高效地处理问题,避免了不必要的重复计算。

(如果你有其他的解法,欢迎留言和大家一起交流,共同学习)~~