如果不会做这道题,2023 年千万不要去炒股,会赔的很惨

134 阅读2分钟

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

2023开年第一题

思路:类比炒股

思路并不复杂,但是这是一道阅读理解题,要耐心地搞懂题意。

我想出题者肯定是一位炒股高手,或者做生意高手,而且赔了个底朝天,所以才出这么一道题来折磨我们[doge][滑稽]🤣🤣。

只要理解清楚股票交易时的成交撮合机制,思路就很简单了。如果我要买,那只要有人出价不高于挂单价,就能成交;反之亦然。

想明白这一点,就很容易想到用优先队列来解了。设置两个优先队列,一个是最大优先,对应买方订单,另一个是最小优先队列,对应卖方订单。一句话:总是期望买到最低,卖到最高。

🦉🐒🐶**所以,如果这道题不会做,2023 年千万不要去炒股,会赔的很惨。**🦉🐒🐶

优先队列和普通队列的区别在于,优先队列的头部元素总是最大的或者最小的。基于二叉堆的优先队列中,入队和出队的代价都是 O(logn)O(\log n)

代码

/*
执行用时:25 ms, 在所有 Java 提交中击败了97.89%的用户
内存消耗:76.3 MB, 在所有 Java 提交中击败了83.55%的用户
通过测试用例:69 / 69
*/
class Solution {
    public int getNumberOfBacklogOrders(int[][] orders) {
        PriorityQueue<Integer> buyQue = new PriorityQueue<>((i1, i2)->orders[i2][0] - orders[i1][0]);
        PriorityQueue<Integer> sellQue = new PriorityQueue<>((i1, i2)->orders[i1][0] - orders[i2][0]);
        for(int i = 0; i < orders.length; i++){
            int[] o = orders[i];
            int type = o[2], price = o[0];
            if(type == 0){ // o是采购订单buy
                while(!sellQue.isEmpty() && o[1] > 0){
                    int[] q = orders[sellQue.peek()];
                    if(q[0] > price)break;
                    int min = Math.min(o[1], q[1]);
                    o[1] -= min;
                    q[1] -= min;
                    if(q[1] == 0)sellQue.poll();
                }
                if(o[1] > 0)buyQue.offer(i);
            }else{ // o是销售订单 sell
                while(!buyQue.isEmpty() && o[1] > 0){
                    int[] q = orders[buyQue.peek()];
                    if(q[0] < price)break;
                    int min = Math.min(o[1], q[1]);
                    o[1] -= min;
                    q[1] -= min;
                    if(q[1] == 0) buyQue.poll();;
                }
                if(o[1] > 0)sellQue.offer(i);
            }
        }

        int ret = 0;
        for(int[] o: orders)ret = (ret + o[1]) % (1000000007);
        return ret;
    }
}

注意事项

有思路后,编码过程有很多细节,一定要想清楚买和卖,处理好各种大于小于,别搞反了。

其次,遇到累加求和越界,要求要用 10e9+7 取模,一定不要写成下面这样,我就是因为这个原因,死都调试不通:

for(int[] o: orders)ret += o[1] % (1000000007);`

复杂度

时间复杂度O(nlogn)O(n\log n)。每个元素都会入队和出队一次,复杂度为 O(xlogx+ylogy)O(x \log x + y \log y),其中 xxyy 分别代表买单和卖单的总数,x+y=nx + y = n。遍历数组累加求和,代价为 (n)(n),所以总复杂度为 O(nlogn)O(n\log n)

空间复杂度O(n)O(n)。两个优先队列的长度加起来,最大为 nn

最后,祝大家 2023 发大财 💰💰!

本文首发于公众号「程序员老宋」,欢迎来逛逛~~