1801. 积压订单中的订单总数

LeetCode 处理积压订单中的订单总数:堆结构模拟实战解析

题目描述

我们在进行订单撮合系统的构建时,可能会遇到如下问题:

给定一个二维整数数组 orders,其中每个 orders[i] = [pricei, amounti, orderTypei] 表示有 amounti 笔订单,类型为 orderTypei,价格为 pricei

  • orderTypei == 0 表示这是一个 采购订单(Buy)
  • orderTypei == 1 表示这是一个 销售订单(Sell)

每条订单在输入中按时间顺序排列,即先于 orders[i+1]

订单匹配规则如下:

  • 若是采购订单(Buy):
    • 可以匹配价格小于等于该订单价格的最便宜销售订单。
  • 若是销售订单(Sell):
    • 可以匹配价格大于等于该订单价格的最贵采购订单。

订单一旦匹配,会消耗对应数量的订单;多余的部分会继续参与撮合或被放入积压订单中。

要求: 所有订单处理完成后,返回积压订单的总数量(对 10 9 + 7 10^9 + 7 109+7 取模)。


解题思路分析

该问题实质上是一个订单撮合系统模拟问题,要求我们实现一个小型交易所的核心撮合逻辑。

关键点分析:

  • 撮合过程是按顺序处理订单,且撮合只发生在订单满足价格条件时。
  • 为了快速获得价格最优的订单进行匹配,我们可以用:
    • 最大堆存储买单(buy):因为要找价格最高的买家。
    • 最小堆存储卖单(sell):因为要找价格最低的卖家。

结构选择:

  • buy_heap: 最大堆,按 -price 存储(Python 的 heapq 是最小堆,所以取反)。
  • sell_heap: 最小堆,按正常 price 存储。

✅ 解题方法:堆模拟撮合

以下是完整的 Python 实现:

import heapq
from typing import List

class Solution:
    def getNumberOfBacklogOrders(self, orders: List[List[int]]) -> int:
        MOD = 10**9 + 7
        buy_heap = []   # 最大堆(按负 price 存储)
        sell_heap = []  # 最小堆(正常 price 存储)

        for price, amount, orderType in orders:
            if orderType == 0:  # buy order
                # 匹配最低价 sell
                while amount > 0 and sell_heap and sell_heap[0][0] <= price:
                    sell_price, sell_amount = heapq.heappop(sell_heap)
                    if sell_amount > amount:
                        heapq.heappush(sell_heap, (sell_price, sell_amount - amount))
                        amount = 0
                    else:
                        amount -= sell_amount
                if amount > 0:
                    heapq.heappush(buy_heap, (-price, amount))
            else:  # sell order
                # 匹配最高价 buy
                while amount > 0 and buy_heap and -buy_heap[0][0] >= price:
                    buy_price, buy_amount = heapq.heappop(buy_heap)
                    if buy_amount > amount:
                        heapq.heappush(buy_heap, (buy_price, buy_amount - amount))
                        amount = 0
                    else:
                        amount -= buy_amount
                if amount > 0:
                    heapq.heappush(sell_heap, (price, amount))

        # 统计剩余积压订单
        total = sum(amount for _, amount in buy_heap + sell_heap)
        return total % MOD

⏱️ 时间与空间复杂度分析

  • 时间复杂度
    每条订单最多被 heappushheappop 一次,复杂度为 O(n log n),其中 n 为订单数量。
  • 空间复杂度
    最多存储 n 条积压订单在两个堆中,复杂度为 O(n)

示例说明

输入:

orders = [
    [10, 5, 0],  # buy 5 @10
    [15, 2, 1],  # sell 2 @15
    [25, 1, 1],  # sell 1 @25
    [30, 4, 0]   # buy 4 @30
]

撮合过程:

  1. buy(10, 5):没有卖单,入 buy_heap ➜ buy_heap=[(-10,5)]
  2. sell(15, 2):找不到 ≥15 的买单 ➜ 入 sell_heap ➜ sell_heap=[(15,2)]
  3. sell(25, 1):同上 ➜ sell_heap=[(15,2),(25,1)]
  4. buy(30, 4):匹配 sell(15,2) 和 sell(25,1) ➜ 剩余 1 笔未匹配 ➜ buy_heap=[(-10,5),(-30,1)]

积压订单总数:5 + 1 = 6

输出:6


更多测试用例

# 所有订单完全匹配,无积压
orders = [
    [10, 2, 0],
    [5, 2, 1]
]
# 输出: 0

# 多次交替撮合
orders = [
    [7, 5, 0],
    [9, 1, 1],
    [5, 2, 1],
    [6, 1, 1],
    [7, 1, 1],
    [10, 2, 0]
]
# 输出: (手动模拟或代码验证)

分析与比较

方法 时间复杂度 空间复杂度 优点 缺点
堆(优先队列) O(n log n) O(n) 高效模拟匹配过程 实现较繁琐,需要注意堆结构细节
简单列表模拟 O(n²) O(n) 结构直观 匹配效率低,超时风险高

因此,使用 最小堆+最大堆 是处理此类问题的最优解法。


️ 可选优化建议

  • 若系统中订单量巨大,可以使用更底层的数据结构如红黑树 (SortedDict) 提高局部修改效率(Python 可用 sortedcontainers)。
  • 将代码中撮合逻辑提取成函数,增强模块化与可读性。
  • 若为高频交易系统场景,可引入异步机制处理订单流入。

总结

这道题本质是一个「堆模拟优先匹配」的问题,考察:

  • 正确建模订单逻辑
  • 合理选择数据结构(最大堆 vs 最小堆)
  • 模拟复杂匹配过程的能力

通过本题可以深刻理解堆的实用价值,并掌握一个交易撮合系统的雏形。

你可能感兴趣的:(python,算法,leetcode,python,开发语言,linux)