LeetCode·每日一题·1801.积压订单中的订单总数·优先队列

作者:小迅
链接:https://leetcode.cn/problems/number-of-orders-in-the-backlog/solutions/2041265/you-xian-dui-lie-zhu-shi-chao-ji-xiang-x-ln8c/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 

题目

 

示例

 

思路

阅读理解题,读着确实难受,不过还挺有意义的。 其实题目描述的就是“价格优先”的竞价规则。 所谓“价格优先”,就是优先成交“出价最高”的“买方”和“出价最低”的“卖方”。 股票市场以及steam里的市场都将这个原则放在第一位。 所谓“积压订单”,就是一个订单池,买方出价和卖方要价没有重叠(否则立即成交)。 我们要根据价格优先原则维护这些订单的“优先级”,很自然地想到 优先队列 。 买方出价越高,优先级越高,所以用大顶堆维护,与之相反,卖方订单用小顶堆维护。 每遇到一个新的订单,就与订单池中另一方的优先级最高的订单(堆顶)比较,并尝试进行交易,直到没有订单可以交易。 维护订单池中的订单数,根据出入调整,最后返回即可

优先队列的实现,我们可以使用队列,堆,哈希表或者数组实现,对于本题 可以使用 大顶堆记录买、小顶堆记录卖来实现优先队列也可以使用哈希表来实现优先队列。

对于哈希表可以使用力扣支持的库实现,不会的可以看看哈希表库实现

代码

//哈希表实现优先队列
int hashSortSell(int* a, int* b){
    return *a > *b;
}

int hashSortBuy(int* a, int* b){
    return *a < *b;
}

typedef struct{
    int price;
    int amount;
    UT_hash_handle hh;
} hashMap;

#define MOD 1000000007

int getNumberOfBacklogOrders(int** orders, int ordersSize, int* ordersColSize){
   //可以哈希表建立buy的降序排列表,sell的升序排列表
    hashMap* buyItem = NULL;
    hashMap* sellItem = NULL;
    hashMap* tmp = NULL;
    hashMap* cur = NULL;
    for(int i = 0; i < ordersSize;i++){
        if(orders[i][2] == 0){
            //buy
            HASH_ITER(hh,sellItem,cur,tmp){
                if(cur && cur->price <= orders[i][0]) {
                    if (cur->amount >= orders[i][1]) {
                        cur->amount -= orders[i][1];
                        //该sell项目可以剔除
                        if (cur->amount == 0) {
                            HASH_DEL(sellItem,cur);
                        }
                        orders[i][1] = 0;
                        break;
                    } else {
                        orders[i][1] -= cur->amount;
                        HASH_DEL(sellItem, cur);
                    }
                } else {
                    //没有找到可以处理的项目,退出
                    break;
                }
            }

            //将该项目加入哈希表中
            HASH_FIND_INT(buyItem,&orders[i][0],tmp);
            if(tmp == NULL) {
                tmp = malloc(sizeof(hashMap));
                tmp->price = orders[i][0];
                tmp->amount = orders[i][1];
                HASH_ADD_INORDER(hh, buyItem, price, sizeof(int), tmp, hashSortBuy);
            } else {
                tmp->amount += orders[i][1];
            }
        } else {
            //sell
            HASH_ITER(hh,buyItem,cur,tmp){
                if(cur && cur->price >= orders[i][0]) {
                    if (cur->amount >= orders[i][1]) {
                        cur->amount -= orders[i][1];
                        //该buy项目可以剔除
                        if (cur->amount == 0) {
                            HASH_DEL(buyItem,cur);
                        }
                        orders[i][1] = 0;
                        break;
                    } else {
                        orders[i][1] -= cur->amount;
                        HASH_DEL(buyItem, cur);
                    }
                } else {
                    //没有找到可以处理的项目,退出
                    break;
                }
            }

            //将该项目加入哈希表中
            HASH_FIND_INT(sellItem,&orders[i][0],tmp);
            if(tmp == NULL) {
                tmp = malloc(sizeof(hashMap));
                tmp->price = orders[i][0];
                tmp->amount = orders[i][1];
                HASH_ADD_INORDER(hh, sellItem, price, sizeof(int), tmp, hashSortSell);
            } else {
                tmp->amount += orders[i][1];
            }
        }
    }

    int ret = 0;
    HASH_ITER(hh,buyItem,cur,tmp){
        if(cur){
            ret = (ret + cur->amount)%MOD;
            HASH_DEL(buyItem,cur);
            free(cur);
        }
    }

    HASH_ITER(hh,sellItem,cur,tmp){
        if(cur){
            ret = (ret + cur->amount)%MOD;
            HASH_DEL(sellItem,cur);
            free(cur);
        }
    }
    
    return ret%MOD;
}


作者:小迅
链接:https://leetcode.cn/problems/number-of-orders-in-the-backlog/solutions/2041265/you-xian-dui-lie-zhu-shi-chao-ji-xiang-x-ln8c/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
//堆实现优先队列
//代码示例   标准堆 存储数据
typedef struct Heap
{
    long long * array;   //存放堆的数组
    long long * num;
    int  capacity;//数组的容量
    int  len;     //已存数组的大小
}Heap;
//#define maxHeap                                         /*大小根堆切换开关*/
int  HeapLen(Heap* hp);                                 //heap获取当前的堆大小
void HeapSwap(long long * pLeft, long long * pRight);                 //heap交换父子结点的数值
bool HeapEmpty(Heap* hp);                               //heap判空
bool HeapFull(Heap* hp);                                //heap判满
long long   HeapGetTop(Heap* hp);                              //heap获取堆顶
void HeapInsert(Heap* hp, long long   dat,long long  num);            //heap向堆的尾部插入1个元素
void HeapDelete(Heap* hp);                              //heap删除堆顶
void HeapAdjustDown(Heap* hp, int parent);              //heap向下调整
void HeapAdjustUp(Heap* hp, int child);                 //heap向上调整
Heap* CreateHeap( int size);                            //heap创建
void heapFree(Heap* hp);                                //heap释放空间
bool maxHeap;

int HeapLen(Heap* hp)
{
    return hp->len;
}

bool HeapEmpty(Heap* hp)          //判空
{
    if (HeapLen(hp) == 1)
    {
        return true;
    }
    return false;
}

bool HeapFull(Heap* hp)          //判满
{
    if (hp->capacity == hp->len)
    {
        return true;
    }
    return false;
}

void HeapSwap(long long * pLeft, long long * pRight)//交换数值
{
    //交换堆中的父子结点
    long long   temp;
    temp = *pLeft;
    *pLeft = *pRight;
    *pRight = temp;
}

long long  HeapGetTop(Heap* hp)
{
    return hp->array[1];
}

void HeapDelete(Heap* hp)//删除堆顶
{
    if (HeapEmpty(hp))
        return;

    //用最后一个元素覆盖堆顶,相当于删除堆顶
    hp->array[1] = hp->array[hp->len - 1];
    hp->num[1]   = hp->num[hp->len - 1];
    hp->len--;//删除最后一个元素 heap长度变短
    HeapAdjustDown(hp, 1);//对第一个元素进行调整
}

void HeapInsert(Heap* hp, long long   dat,long long  num)
{
    if (HeapFull(hp))
        return;
    int child = 0;
    int parent = 0;
    //插入到最后一个元素的下一个位置
    hp->array[hp->len] = dat;
    hp->num[hp->len] = num;
    hp->len++;
    //调整刚插入元素,
    //因为插入的是堆的尾部,需要堆向上调整
    HeapAdjustUp(hp, hp->len - 1);
}

Heap* CreateHeap( int size)//创建
{
    Heap* heap = (Heap*)malloc(sizeof(Heap));
    int   heapLen = size + 1;//长度比size的长度大1才行
    //给堆申请空间,初始化
    heap->array = (long long *)malloc(sizeof(long long ) * heapLen);
    heap->num = (long long *)malloc(sizeof(long long ) * heapLen);

    heap->capacity = heapLen;     //容量
    heap->len = 1;     //当前大小
    return heap;
}

void HeapAdjustDown(Heap* hp, int parent)//向下调整
{
    //标记左右孩子中最小孩子
    int child = 2 * parent;            //左孩子为2*parent  右孩子为 2*parent +1
    int len = hp->len;

    while (child < len)
    {
        if( maxHeap)      
        {
            //大根堆 选最大的
            //有右子树时 ,找左右孩子中最大的孩子 
            if ((child + 1 < len) && hp->array[child] < hp->array[child + 1])
                child = child + 1;

            //最大孩子大于双亲时 ,孩子与双亲数值交换,否则说明已经调好,不用继续
            if (hp->array[child] > hp->array[parent])
            {
                HeapSwap(&hp->array[child], &hp->array[parent]);
                HeapSwap(&hp->num[child], &hp->num[parent]);
                parent = child;
                child = parent << 1;
            }
            else
            {
                return;
            }
        }
        else
        {
            //小根堆  选最小的
            //有右子树时 ,找左右孩子中最小的孩子 
            if ((child + 1 < len) && hp->array[child] > hp->array[child + 1])
                child = child + 1;

            //最小孩子小于双亲时 ,孩子与双亲数值交换,否则说明已经调好,不用继续
            if (hp->array[child] < hp->array[parent])
            {
                HeapSwap(&hp->array[child], &hp->array[parent]);
                HeapSwap(&hp->num[child], &hp->num[parent]);
                parent = child;
                child = parent << 1;
            }
            else
                return;
        }
    }
}

void HeapAdjustUp(Heap* hp, int child)//向上调整
{
    //得到父母结点的位置
    int parent = child / 2;
    
    if( maxHeap)    
    {
        //大根堆选择大的
        //循环迭代从child当前位置一直迭代到0位置即对顶
        while (child > 1)
        {
            if (hp->array[child] > hp->array[parent])
            {
                HeapSwap(&hp->array[child], &hp->array[parent]);
                HeapSwap(&hp->num[child], &hp->num[parent]);
                child = parent;
                parent = child/2;
            }
            else
                return;
        }
    }
    else
    {
        //小根堆选择小的
        //循环迭代从child当前位置一直迭代到0位置即对顶
        while (child > 1)
        {
            if (hp->array[child] < hp->array[parent])
            {
                HeapSwap(&hp->array[child], &hp->array[parent]);
                HeapSwap(&hp->num[child], &hp->num[parent]);
                child = parent;
                parent = child/2;
            }
            else
                return;
        }
    }
}

void heapFree(Heap* hp)
{
    free(hp->array);
    free(hp);
}

int getNumberOfBacklogOrders(int** orders, int ordersSize, int* ordersColSize)
{
    //买最大堆
    //卖最小堆
    Heap * buyHeap  = CreateHeap(ordersSize);
    Heap * sellHeap = CreateHeap(ordersSize);
    for(int i = 0; i<ordersSize; i++)
    {
        if(orders[i][2] == 1)
        {
            //卖 最小堆
            maxHeap = false;
            HeapInsert(sellHeap, (long long )orders[i][0], (long long )orders[i][1]);
        }
        else
        {
            //买 最大堆
            maxHeap = true;
            HeapInsert(buyHeap, (long long )orders[i][0], (long long )orders[i][1]);
        }


        //买和卖都不为空
        //检查买的最大值,大于卖的最小值
        while(!HeapEmpty(sellHeap) && !HeapEmpty(buyHeap) && HeapGetTop(buyHeap)  >= HeapGetTop(sellHeap) )
        {
            int BuyNum  = buyHeap->num[1];
            int SellNum = sellHeap->num[1];

            if(BuyNum ==  SellNum)
            {
                //删掉卖的订单
                maxHeap = false;
                HeapDelete(sellHeap);

                //删掉买的订单
                maxHeap = true;
                HeapDelete(buyHeap);
            }
            else if(BuyNum > SellNum)
            {
                //删掉卖的订单
                maxHeap = false;
                HeapDelete(sellHeap);

                //买的订单放回去
                buyHeap->num[1] -= SellNum;
            }
            else
            {
                //卖的订单放回去
                sellHeap->num[1] -= BuyNum;

                 //删掉买的订单
                maxHeap = true;
                HeapDelete(buyHeap);
            }
        }
    }

    long long count = 0;
    while(!HeapEmpty(sellHeap))
    {
        count =  (count + sellHeap->num[1])%1000000007;
        HeapDelete(sellHeap);
    }

    while(!HeapEmpty(buyHeap))
    {
        count =  (count + buyHeap->num[1])%1000000007;
        HeapDelete(buyHeap);
    }

    return count%1000000007;
}


作者:小迅
链接:https://leetcode.cn/problems/number-of-orders-in-the-backlog/solutions/2041265/you-xian-dui-lie-zhu-shi-chao-ji-xiang-x-ln8c/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值