「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」
题目介绍
原题目比较长,描述也是晦涩难懂,我用大白话对题目做个介绍(需要看原题的请戳上方链接)
- 题目会传进来一个二维数组,数组的结构是这样的
[[price1, amount1, orderType1], [price2, amount2, orderType2] ... ]
price: 表示订单的价格orderType: 表示订单类型 (0:采购订单, 1:销售订单)amount: 表示价格和类型都相同的订单的数量
- 题目规则
- 如果一批订单是购买订单,则看
销售积压订单中是否存在价格小于等于购买订单价格的订单,如果存在,则删除购买订单或者销售积压订单中小于等于购买订单价格的订单的 较小值,购买订单多出的订单数加入到购买积压订单中 - 如果一批订单是销售订单,则看
购买积压订单中是否存在价格大于等于销售订单价格的订单,如果存在,则删除销售订单或者购买积压订单中大于等于销售订单价格的订单的 较小值,销售订单多出的订单数加入到销售积压订单中 - 最后返回
销售积压订单和购买积压订单的订单总数对10^9 + 7取余的结果
示例1
示例2
解题思路
此题关键是要理解订单之间抵消的规则,购买订单是从销售积压订单中的最小值开始比较,因此可以用一个小顶堆维护 销售积压订单;销售订单是从购买订单中的最大值开始比较,因此用一个大顶堆维护 购买积压订单
在此题中,订单的总数可能很大,因此不能将每一个订单都放到堆中,这样会导致内存溢出,最好的做法是以 {price: '订单价格', amount: '订单数量'} 来进行存储,每次抵消堆顶元素一定数量的订单,再重新将剩余的积压订单插入堆中
解题步骤
- 创建一个大顶堆
buy存放购买积压订单,创建一个小顶堆sell存放销售积压订单,变量total实时保存当前积压的订单总数 - 遍历订单列表:
- 如果当前订单是购买订单,则看
销售积压订单中是否有订单- 如果没有,将当前这批购买订单的
{price: '订单价格', amount: '订单数量'}插入购买积压订单buy中,total加上这批购买订单的数量 - 如果有,弹出
销售积压订单sell的堆顶元素- 如果堆顶订单的数量 大于 购买订单的数量,将堆顶订单的数量减去购买订单的数量,然后重新插入到
销售积压订单sell中,total减去这批购买订单的数量 - 如果堆顶订单的数量 小于 购买订单的数量,将购买订单的数量减去堆顶订单的数量,
total减去堆顶订单的数量,继续弹出销售积压订单sell的堆顶元素和剩余数量的购买订单进行比较,并重复以上步骤 - 最后如果购买订单有剩余,将剩余的购买订单价格和数量插入到
购买积压订单buy中
- 如果堆顶订单的数量 大于 购买订单的数量,将堆顶订单的数量减去购买订单的数量,然后重新插入到
- 如果没有,将当前这批购买订单的
- 如果当前订单是销售订单,则看
购买积压订单中是否有订单- 如果没有,将当前这批销售订单的
{price: '订单价格', amount: '订单数量'}插入销售积压订单sell中,total加上这批销售订单的数量 - 如果有,弹出
购买积压订单buy的堆顶元素- 如果堆顶订单的数量 大于 销售订单的数量,将堆顶订单的数量减去销售订单的数量,然后重新插入到
购买积压订单buy中,total减去这批销售订单的数量 - 如果堆顶订单的数量 小于 销售订单的数量,将销售订单的数量减去堆顶订单的数量,
total减去堆顶订单的数量,继续弹出购买积压订单buy的堆顶元素和剩余数量的销售订单进行比较,并重复以上步骤 - 最后如果销售订单有剩余,将剩余的销售订单价格和数量插入到
销售积压订单sell中
- 如果堆顶订单的数量 大于 销售订单的数量,将堆顶订单的数量减去销售订单的数量,然后重新插入到
- 如果没有,将当前这批销售订单的
- 返回结果
积压订单总数 total % (Math.pow(10, 9) + 7)
解题代码
var getNumberOfBacklogOrders = function(orders) {
// 购买积压订单
const buy = new Heap(1)
// 销售积压订单
const sell = new Heap(-1)
// 积压订单总数
let total = 0
for (let [price, amount, orderType] of orders) {
if (orderType === 0) { // 购买
// 如果销售积压订单不为空 && 堆顶的价格小于等于购买订单的价格 && 购买订单数量大于0
while (sell.size() && sell.top().price <= price && amount > 0) {
const head = sell.pop()
if (amount < head.amount) { // 如果购买订单数量小于堆顶订单数量
// 将多出的堆顶订单数量重新插入销售积压订单中
sell.push({price: head.price, amount: head.amount - amount})
// 积压订单总数少了被购买订单抵消的部分
total -= amount
// 购买订单数量置为0
amount = 0
} else { // 购买订单数量大于等于堆顶订单数量
// 购买订单数量少了被堆顶订单抵消的部分
amount -= head.amount
// 积压订单总数少了被购买订单抵消的部分
total -= head.amount
}
}
// 如果购买订单有剩余,将剩余的购买订单插入到购买积压订单
if (amount > 0) {
buy.push({price, amount})
total += amount
}
} else { // 销售
// 如果购买积压订单不为空 && 堆顶的价格大于等于销售订单的价格 && 销售订单数量大于0
while (buy.size() && buy.top().price >= price && amount > 0) {
const head = buy.pop()
if (amount < head.amount) { // 如果销售订单数量小于堆顶订单数量
// 将多出的堆顶订单数量重新插入购买积压订单中
buy.push({price: head.price, amount: head.amount - amount})
// 积压订单总数少了被销售订单抵消的部分
total -= amount
// 销售订单数量置为0
amount = 0
} else { // 销售订单数量大于等于堆顶订单数量
// 销售订单数量少了被堆顶订单抵消的部分
amount -= head.amount
// 积压订单总数少了被销售订单抵消的部分
total -= head.amount
}
}
// 如果销售订单有剩余,将剩余的销售订单插入到销售积压订单
if (amount > 0) {
sell.push({price, amount})
total += amount
}
}
}
return total % (Math.pow(10, 9) + 7)
};
// 堆类
class Heap {
constructor(type) {
this.arr = []
// 根据 type 的值判断生成大顶堆还是生成小顶堆:-1 小顶堆 1 大顶堆
this.type = type
}
// 返回堆的大小
size() {
return this.arr.length
}
// 返回堆顶元素
top() {
return this.arr[0]
}
// 往堆中插入元素
push(val) {
this.arr.push(val)
this._sortBack()
}
// 弹出堆顶元素
pop() {
const val = this.arr[0]
const back = this.arr.pop()
if (this.size()) {
this.arr[0] = back
this._sortFront()
}
return val
}
// 向上调整堆结构
_sortBack() {
let i = this.size() - 1
if (this.type === -1) {
while (i > 0 && this.arr[i].price < this.arr[Math.floor((i - 1) / 2)].price) {
[this.arr[i], this.arr[Math.floor((i - 1) / 2)]] = [this.arr[Math.floor((i - 1) / 2)], this.arr[i]]
i = Math.floor((i - 1) / 2)
}
} else {
while (i > 0 && this.arr[i].price > this.arr[Math.floor((i - 1) / 2)].price) {
[this.arr[i], this.arr[Math.floor((i - 1) / 2)]] = [this.arr[Math.floor((i - 1) / 2)], this.arr[i]]
i = Math.floor((i - 1) / 2)
}
}
}
// 向下调整堆结构
_sortFront() {
let i = 0
if (this.type === -1) {
while (i * 2 + 1 < this.size()) {
let temp = i
if (this.arr[temp].price > this.arr[i * 2 + 1].price) temp = i * 2 + 1
if (i * 2 + 2 < this.size() && this.arr[temp].price > this.arr[i * 2 + 2].price) temp = i * 2 + 2
if (temp === i) break
[this.arr[temp], this.arr[i]] = [this.arr[i], this.arr[temp]]
i = temp
}
} else {
while (i * 2 + 1 < this.size()) {
let temp = i
if (this.arr[temp].price < this.arr[i * 2 + 1].price) temp = i * 2 + 1
if (i * 2 + 2 < this.size() && this.arr[temp].price < this.arr[i * 2 + 2].price) temp = i * 2 + 2
if (temp === i) break
[this.arr[temp], this.arr[i]] = [this.arr[i], this.arr[temp]]
i = temp
}
}
}
}