如何在Node.js中优化演出门票购买算法?算法问题解析
演唱会购票时间计算:Node.js 优化方案
Hey 朋友,咱们来一步步解决这个演唱会门票的时间计算问题,从直观的模拟方法到高效的数学优化方案都给你理清楚~
首先得把问题的规则再明确下:
售票规则:每人每次只能买1张票,要是想买多张,必须重新排到队尾;杰西现在在队伍里,需要买N张票,给定所有购票者的初始购票需求列表,得算出杰西买完所有票总共花了多少时间。
先说说最直观的暴力模拟法(适合小数据量)
最容易想到的就是直接模拟整个排队过程:
- 用队列来模拟队伍,每一轮挨个处理每个购票者:
- 如果这个人还有票要购买,时间加1,把他的购票需求减1;
- 如果这个人是杰西,而且他的需求已经减到0了,直接返回当前时间就行;
- 要是这个人还有剩余需求,就把他放到队尾重新排队。
不过这种方法有个问题:如果队伍里人特别多,或者每个人要买的票特别多,那模拟的轮次会超级多,性能会拉胯。比如要是有1000个人每人买1000张票,那得循环100万次,想想都慢。
暴力法的Node.js实现
function calculateTimeBruteforce(people, jesseIndex) { let time = 0; const queue = [...people]; let jesseRemaining = queue[jesseIndex]; let currentJessePos = jesseIndex; while (jesseRemaining > 0) { const currentPerson = queue.shift(); if (currentPerson > 0) { time++; // 处理杰西的剩余票数 if (currentJessePos === 0) { jesseRemaining--; if (jesseRemaining === 0) { return time; } // 杰西买完一张,排到队尾,新位置是当前队列长度(因为刚shift了一个元素) currentJessePos = queue.length; } else { currentJessePos--; } // 还有需求的话,放回队尾 queue.push(currentPerson - 1); } else { // 这个人已经买完了,不用再排队,调整杰西的位置 if (currentJessePos > 0) { currentJessePos--; } } } return time; } // 测试示例:队伍是[2,3,2],杰西在第2个位置(索引1),需要买3张 console.log(calculateTimeBruteforce([2,3,2], 1)); // 输出7,和实际流程一致
重点来啦:O(n)时间的优化方案
其实我们完全不用模拟每一轮,用数学推导就能直接算出总时间,效率直接拉满!
核心思路是:计算杰西买完所有票的过程中,每一个购票者总共会占用多少时间,把这些时间加起来就是总耗时。
具体分三种情况:
- 杰西前面的人:他们在杰西买完所有票的过程中,最多能买
min(自己的需求, 杰西需要的票数)次——因为杰西买k张要排k次队,前面的人每一轮都能买,直到自己买完或者杰西买完。 - 杰西自己:肯定是买k次,贡献k单位时间。
- 杰西后面的人:他们最多能买
min(自己的需求, 杰西需要的票数-1)次——因为杰西在第k次买完票之后就结束了,后面的人在第k轮时杰西已经完成购票,不会再轮到他们。
这样我们只需要遍历一次购票列表,就能算出总时间,不管数据量多大,都能瞬间出结果。
优化方案的Node.js实现
function calculateTimeOptimized(people, jesseIndex) { const jesseNeed = people[jesseIndex]; let totalTime = 0; for (let i = 0; i < people.length; i++) { if (i < jesseIndex) { // 前面的人:最多参与jesseNeed轮 totalTime += Math.min(people[i], jesseNeed); } else if (i === jesseIndex) { // 杰西自己的k次 totalTime += jesseNeed; } else { // 后面的人:最多参与jesseNeed-1轮 totalTime += Math.min(people[i], jesseNeed - 1); } } return totalTime; } // 同样测试示例 console.log(calculateTimeOptimized([2,3,2], 1)); // 输出7,和暴力法结果一致
验证一下逻辑
拿示例[2,3,2],杰西需要3张票:
- 前面的人需要2张,贡献
min(2,3)=2; - 杰西自己贡献3;
- 后面的人需要2张,贡献
min(2,3-1)=2;
总时间2+3+2=7,和模拟的实际流程完全匹配: - 第1轮:所有人各买1张,时间+3;
- 第2轮:所有人各买1张,时间+3(累计6);
- 第3轮:轮到杰西买最后1张,时间+1(累计7),结束。
为啥优化方案更牛?
如果遇到极端情况,比如10万人每人买100万张票,暴力模拟法会直接超时,而优化方案只需要遍历10万次,眨眼就能出结果,性能差距不是一星半点。
内容的提问来源于stack exchange,提问作者Akhilesh Kumar
相关产品推荐
相关产品推荐

