Medium

题目描述

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

订单类型 orderTypei 可以分为两种:

  • 0 表示这是一批采购订单 buy
  • 1 表示这是一批销售订单 sell

注意,orders[i] 表示一批共 amounti 笔的独立订单,这些订单的价格和类型相同。对于所有有效的 i,由 orders[i] 表示的所有订单提交时间均早于 orders[i+1] 表示的所有订单。

存在一个由未执行订单组成的积压订单,积压订单最初是空的。提交订单时,会发生以下情况:

  • 如果该订单是一笔采购订单,则查看积压订单中价格最低的销售订单。如果该销售订单的价格小于或等于当前采购订单的价格,则匹配并执行这些订单,并将销售订单从积压订单中删除。否则,采购订单将会添加到积压订单中。
  • 反之亦然,如果该订单是一笔销售订单,则查看积压订单中价格最高的采购订单。如果该采购订单的价格大于或等于当前销售订单的价格,则匹配并执行这些订单,并将采购订单从积压订单中删除。否则,销售订单将会添加到积压订单中。

输入所有订单后,返回积压订单中的订单总数。由于数字可能很大,所以需要返回对 10^9 + 7 取余的结果。

示例 1:

输入:orders = [[10,5,0],[15,2,1],[25,1,1],[30,4,0]]
输出:6
解释:输入订单后会发生下述情况:
- 提交 5 笔采购订单,价格为 10 。没有销售订单,所以这 5 笔订单添加到积压订单中。
- 提交 2 笔销售订单,价格为 15 。没有价格大于或等于 15 的采购订单,所以这 2 笔订单添加到积压订单中。
- 提交 1 笔销售订单,价格为 25 。没有价格大于或等于 25 的采购订单,所以这 1 笔订单添加到积压订单中。
- 提交 4 笔采购订单,价格为 30 。前 2 笔采购订单与价格最低(价格为 15)的 2 笔销售订单匹配,从积压订单中删除这 2 笔销售订单。第 3 笔采购订单与价格最低(价格为 25)的 1 笔销售订单匹配,从积压订单中删除这 1 笔销售订单。积压订单中不再有销售订单,所以第 4 笔采购订单添加到积压订单中。
最终,积压订单中有 5 笔价格为 10 的采购订单,和 1 笔价格为 30 的采购订单。所以积压订单中的订单总数为 6 。

示例 2:

输入:orders = [[7,1000000000,1],[15,3,0],[5,999999995,0],[5,1,1]]
输出:999999984

提示:

  • 1 <= orders.length <= 10^5
  • orders[i].length == 3
  • 1 <= pricei, amounti <= 10^9
  • orderTypei01

解题思路

这道题的核心是模拟订单匹配的过程,需要使用两个堆来维护积压订单:

思路分析:

  1. 数据结构选择

    • 采购订单(buy orders):使用最大堆按价格排序,因为我们需要找到价格最高的采购订单来匹配销售订单
    • 销售订单(sell orders):使用最小堆按价格排序,因为我们需要找到价格最低的销售订单来匹配采购订单
  2. 订单匹配逻辑

    • 对于采购订单:找积压中价格最低的销售订单,如果销售价格 ≤ 采购价格,则匹配
    • 对于销售订单:找积压中价格最高的采购订单,如果采购价格 ≥ 销售价格,则匹配
    • 匹配时要处理数量,可能需要部分匹配
  3. 实现细节

    • 堆中存储 [价格, 数量] 的配对
    • 匹配过程中,如果一方订单完全匹配完,从堆中移除;如果部分匹配,更新剩余数量
    • 最后统计所有积压订单的总数量,注意取模
  4. 优化考虑

    • 由于数据规模较大(10^9),需要使用 long long 避免溢出
    • 匹配过程要高效,堆操作的时间复杂度为 O(log n)

代码实现

class Solution {
public:
    int getNumberOfBacklogOrders(vector<vector<int>>& orders) {
        const int MOD = 1e9 + 7;
        
        // 采购订单:最大堆(按价格)
        priority_queue<pair<int, long long>> buyOrders;
        // 销售订单:最小堆(按价格)
        priority_queue<pair<int, long long>, vector<pair<int, long long>>, greater<pair<int, long long>>> sellOrders;
        
        for (auto& order : orders) {
            int price = order[0];
            long long amount = order[1];
            int type = order[2];
            
            if (type == 0) { // 采购订单
                while (amount > 0 && !sellOrders.empty() && sellOrders.top().first <= price) {
                    auto [sellPrice, sellAmount] = sellOrders.top();
                    sellOrders.pop();
                    
                    long long matched = min(amount, sellAmount);
                    amount -= matched;
                    sellAmount -= matched;
                    
                    if (sellAmount > 0) {
                        sellOrders.push({sellPrice, sellAmount});
                    }
                }
                if (amount > 0) {
                    buyOrders.push({price, amount});
                }
            } else { // 销售订单
                while (amount > 0 && !buyOrders.empty() && buyOrders.top().first >= price) {
                    auto [buyPrice, buyAmount] = buyOrders.top();
                    buyOrders.pop();
                    
                    long long matched = min(amount, buyAmount);
                    amount -= matched;
                    buyAmount -= matched;
                    
                    if (buyAmount > 0) {
                        buyOrders.push({buyPrice, buyAmount});
                    }
                }
                if (amount > 0) {
                    sellOrders.push({price, amount});
                }
            }
        }
        
        long long result = 0;
        while (!buyOrders.empty()) {
            result = (result + buyOrders.top().second) % MOD;
            buyOrders.pop();
        }
        while (!sellOrders.empty()) {
            result = (result + sellOrders.top().second) % MOD;
            sellOrders.pop();
        }
        
        return result;
    }
};
class Solution:
    def getNumberOfBacklogOrders(self, orders: List[List[int]]) -> int:
        import heapq
        
        MOD = 10**9 + 7
        
        # 采购订单:最大堆(用负数实现)
        buy_orders = []  # [(-price, amount)]
        # 销售订单:最小堆
        sell_orders = []  # [(price, amount)]
        
        for price, amount, order_type in orders:
            if order_type == 0:  # 采购订单
                while amount > 0 and sell_orders and sell_orders[0][0] <= price:
                    sell_price, sell_amount = heapq.heappop(sell_orders)
                    matched = min(amount, sell_amount)
                    amount -= matched
                    sell_amount -= matched
                    
                    if sell_amount > 0:
                        heapq.heappush(sell_orders, (sell_price, sell_amount))
                
                if amount > 0:
                    heapq.heappush(buy_orders, (-price, amount))
            
            else:  # 销售订单
                while amount > 0 and buy_orders and -buy_orders[0][0] >= price:
                    neg_buy_price, buy_amount = heapq.heappop(buy_orders)
                    matched = min(amount, buy_amount)
                    amount -= matched
                    buy_amount -= matched
                    
                    if buy_amount > 0:
                        heapq.heappush(buy_orders, (neg_buy_price, buy_amount))
                
                if amount > 0:
                    heapq.heappush(sell_orders, (price, amount))
        
        result = 0
        for _, amount in buy_orders:
            result = (result + amount) % MOD
        for _, amount in sell_orders:
            result = (result + amount) % MOD
        
        return result
public class Solution {
    public int GetNumberOfBacklogOrders(int[][] orders) {
        const int MOD = 1000000007;
        
        // 采购订单:最大堆
        var buyOrders = new PriorityQueue<(int price, long amount), int>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
        // 销售订单:最小堆
        var sellOrders = new PriorityQueue<(int price, long amount), int>();
        
        foreach (var order in orders) {
            int price = order[0];
            long amount = order[1];
            int type = order[2];
            
            if (type == 0) { // 采购订单
                while (amount > 0 && sellOrders.Count > 0) {
                    var (sellPrice, sellAmount) = sellOrders.Peek();
                    if (sellPrice > price) break;
                    
                    sellOrders.Dequeue();
                    long matched = Math.Min(amount, sellAmount);
                    amount -= matched;
                    sellAmount -= matched;
                    
                    if (sellAmount > 0) {
                        sellOrders.Enqueue((sellPrice, sellAmount), sellPrice);
                    }
                }
                if (amount > 0) {
                    buyOrders.Enqueue((price, amount), price);
                }
            } else { // 销售订单
                while (amount > 0 && buyOrders.Count > 0) {
                    var (buyPrice, buyAmount) = buyOrders.Peek();
                    if (buyPrice < price) break;
                    
                    buyOrders.Dequeue();
                    long matched = Math.Min(amount, buyAmount);
                    amount -= matched;
                    buyAmount -= matched;
                    
                    if (buyAmount > 0) {
                        buyOrders.Enqueue((buyPrice, buyAmount), buyPrice);
                    }
                }
                if (amount > 0) {
                    sellOrders.Enqueue((price, amount), price);
                }
            }
        }
        
        long result = 0;
        while (buyOrders.Count > 0) {
            result = (result + buyOrders.Dequeue().amount) % MOD;
        }
        while (sellOrders.Count > 0) {
            result = (result + sellOrders.Dequeue().amount) % MOD;
        }
        
        return (int)result;
    }
}
var getNumberOfBacklogOrders = function(orders) {
    const buyOrders = new MaxPriorityQueue({ priority: (x) => x[0] });
    const sellOrders = new MinPriorityQueue({ priority: (x) => x[0] });
    
    for (let [price, amount, type] of orders) {
        if (type === 0) { // buy order
            while (amount > 0 && !sellOrders.isEmpty() && sellOrders.front().element[0] <= price) {
                const [sellPrice, sellAmount] = sellOrders.dequeue().element;
                const matched = Math.min(amount, sellAmount);
                amount -= matched;
                if (sellAmount > matched) {
                    sellOrders.enqueue([sellPrice, sellAmount - matched]);
                }
            }
            if (amount > 0) {
                buyOrders.enqueue([price, amount]);
            }
        } else { // sell order
            while (amount > 0 && !buyOrders.isEmpty() && buyOrders.front().element[0] >= price) {
                const [buyPrice, buyAmount] = buyOrders.dequeue().element;
                const matched = Math.min(amount, buyAmount);
                amount -= matched;
                if (buyAmount > matched) {
                    buyOrders.enqueue([buyPrice, buyAmount - matched]);
                }
            }
            if (amount > 0) {
                sellOrders.enqueue([price, amount]);
            }
        }
    }
    
    let total = 0;
    const MOD = 1000000007;
    
    while (!buyOrders.isEmpty()) {
        total = (total + buyOrders.dequeue().element[1]) % MOD;
    }
    
    while (!sellOrders.isEmpty()) {
        total = (total + sellOrders.dequeue().element[1]) % MOD;
    }
    
    return total;
};

复杂度分析

指标复杂度
时间-
空间-